]> Zhao Yanbai Git Server - minix.git/commitdiff
Import usr.sbin/installboot.
authorEvgeniy Ivanov <lolkaantimat@gmail.com>
Tue, 10 Jan 2012 08:46:52 +0000 (12:46 +0400)
committerBen Gras <ben@minix3.org>
Thu, 9 Feb 2012 17:48:13 +0000 (18:48 +0100)
28 files changed:
tools/nbsd_ports
usr.sbin/installboot/Makefile [new file with mode: 0644]
usr.sbin/installboot/arch/alpha.c [new file with mode: 0644]
usr.sbin/installboot/arch/amiga.c [new file with mode: 0644]
usr.sbin/installboot/arch/emips.c [new file with mode: 0644]
usr.sbin/installboot/arch/ews4800mips.c [new file with mode: 0644]
usr.sbin/installboot/arch/hp300.c [new file with mode: 0644]
usr.sbin/installboot/arch/hp700.c [new file with mode: 0644]
usr.sbin/installboot/arch/i386.c [new file with mode: 0644]
usr.sbin/installboot/arch/landisk.c [new file with mode: 0644]
usr.sbin/installboot/arch/macppc.c [new file with mode: 0644]
usr.sbin/installboot/arch/news.c [new file with mode: 0644]
usr.sbin/installboot/arch/next68k.c [new file with mode: 0644]
usr.sbin/installboot/arch/pmax.c [new file with mode: 0644]
usr.sbin/installboot/arch/sparc.c [new file with mode: 0644]
usr.sbin/installboot/arch/sparc64.c [new file with mode: 0644]
usr.sbin/installboot/arch/sun68k.c [new file with mode: 0644]
usr.sbin/installboot/arch/vax.c [new file with mode: 0644]
usr.sbin/installboot/arch/x68k.c [new file with mode: 0644]
usr.sbin/installboot/bbinfo.c [new file with mode: 0644]
usr.sbin/installboot/ext2fs.c [new file with mode: 0644]
usr.sbin/installboot/ffs.c [new file with mode: 0644]
usr.sbin/installboot/fstypes.c [new file with mode: 0644]
usr.sbin/installboot/installboot.8 [new file with mode: 0644]
usr.sbin/installboot/installboot.c [new file with mode: 0644]
usr.sbin/installboot/installboot.h [new file with mode: 0644]
usr.sbin/installboot/machines.c [new file with mode: 0644]
usr.sbin/installboot/sum.c [new file with mode: 0644]

index e4830d47f720031ecc36b4eda7345ef41c7ab3dc..9c6e5f9f79542b03a2e342c43d0ee1d95106c626 100644 (file)
@@ -33,6 +33,7 @@ usr.bin/seq           src/usr.bin/seq
 usr.bin/man            src/usr.bin/man
 usr.bin/apropos                src/usr.bin/apropos
 usr.bin/mdocml         src/external/bsd/mdocml
+usr.sbin/installboot   src/usr.sbin/installboot
 usr.sbin/pwd_mkdb      src/usr.sbin/pwd_mkdb
 usr.sbin/user          src/usr.sbin/user
 usr.sbin/vipw          src/usr.sbin/vipw
diff --git a/usr.sbin/installboot/Makefile b/usr.sbin/installboot/Makefile
new file mode 100644 (file)
index 0000000..b631a32
--- /dev/null
@@ -0,0 +1,54 @@
+#      $NetBSD: Makefile,v 1.46 2011/08/14 17:50:16 christos Exp $
+#
+
+.include <bsd.own.mk>
+
+PROG=  installboot
+MAN=   installboot.8
+SRCS=  installboot.c sum.c machines.c fstypes.c
+
+
+ARCH_XLAT= amd64-i386.c news68k-news.c newsmips-news.c
+ARCH_XLAT+= sun2-sun68k.c sun3-sun68k.c
+
+.if !defined(SMALLPROG) && !defined(ARCH_FILES)
+ARCH_FILES=  alpha.c amiga.c emips.c ews4800mips.c hp300.c hp700.c i386.c
+ARCH_FILES+= landisk.c macppc.c news.c next68k.c pmax.c
+ARCH_FILES+= sparc.c sparc64.c sun68k.c vax.c x68k.c
+.else
+ARCH_FILES?= ${ARCH_XLAT:M${MACHINE}-*:S/${MACHINE}-//}
+.if empty(ARCH_FILES)
+ARCH_FILES= ${MACHINE}.c
+.endif
+.endif
+
+SRCS+=${ARCH_FILES}
+
+.if empty(ARCH_FILES:C/(macppc|news|sparc|sun68k|x68k)/stg2/:Mstg2.c)
+CPPFLAGS       += -DNO_STAGE2
+.else
+SRCS+= bbinfo.c
+
+# fstypes are only needed for 'stage2' and then only from bbinfo.
+SRCS+= ffs.c
+.if SMALLPROG
+CPPFLAGS+=     -DNO_FFS_SWAP
+.else
+SRCS+= ffs_bswap.c
+.endif
+#SRCS+= ext2fs.c ext2fs_bswap.c
+.endif
+
+UFSSRC=                ${NETBSDSRCDIR}/sys/ufs
+CPPFLAGS+=     -I${.CURDIR} -I.
+.PATH:         ${.CURDIR}/arch ${UFSSRC}/ffs ${UFSSRC}/ext2fs
+
+.if !defined(HOSTPROGNAME)
+.if defined(HAVE_GCC) || defined(HAVE_PCC)
+.for f in i386 macppc
+COPTS.${f}.c+=  -Wno-pointer-sign
+.endfor
+.endif
+.endif
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/installboot/arch/alpha.c b/usr.sbin/installboot/arch/alpha.c
new file mode 100644 (file)
index 0000000..e2de898
--- /dev/null
@@ -0,0 +1,451 @@
+/*     $NetBSD: alpha.c,v 1.21 2011/08/14 17:50:17 christos Exp $      */
+
+/*-
+ * 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.
+ *
+ * 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) 1999 Ross Harvey.  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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Ross Harvey
+ *     for the NetBSD Project.
+ * 4. 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) 1999 Christopher G. Demetriou.  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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Christopher G. Demetriou
+ *     for the NetBSD Project.
+ * 4. 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(__lint)
+__RCSID("$NetBSD: alpha.c,v 1.21 2011/08/14 17:50:17 christos Exp $");
+#endif /* !__lint */
+
+#include <sys/param.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"
+
+#define        SUN_DKMAGIC     55998           /* XXX: from <dev/sun/disklabel.h> */
+
+static void    resum(ib_params *, struct alpha_boot_block * const bb,
+                       uint16_t *bb16);
+static void    sun_bootstrap(ib_params *, struct alpha_boot_block * const);
+static void    check_sparc(const struct alpha_boot_block * const,
+                           const char *);
+
+static int alpha_clearboot(ib_params *);
+static int alpha_setboot(ib_params *);
+
+struct ib_mach ib_mach_alpha =
+       { "alpha", alpha_setboot, alpha_clearboot, no_editboot,
+               IB_STAGE1START | IB_ALPHASUM | IB_APPEND | IB_SUNSUM };
+
+static int
+alpha_clearboot(ib_params *params)
+{
+       struct alpha_boot_block bb;
+       uint64_t                cksum;
+       ssize_t                 rv;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(sizeof(struct alpha_boot_block) == ALPHA_BOOT_BLOCK_BLOCKSIZE);
+
+       if (params->flags & (IB_STAGE1START | IB_APPEND)) {
+               warnx("Can't use `-b bno' or `-o append' with `-c'");
+               return (0);
+       }
+
+       rv = pread(params->fsfd, &bb, sizeof(bb), ALPHA_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);
+       }
+       ALPHA_BOOT_BLOCK_CKSUM(&bb, &cksum);
+       if (cksum != bb.bb_cksum) {             // XXX check bb_cksum endian?
+               warnx(
+           "Old boot block checksum invalid (was %#llx, calculated %#llx)",
+                   (unsigned long long)le64toh(bb.bb_cksum),
+                   (unsigned long long)le64toh(cksum));
+               warnx("Boot block invalid");
+               return (0);
+       }
+
+       if (params->flags & IB_VERBOSE) {
+               printf("Old bootstrap start sector: %llu\n",
+                   (unsigned long long)le64toh(bb.bb_secstart));
+               printf("Old bootstrap size:         %llu\n",
+                   (unsigned long long)le64toh(bb.bb_secsize));
+               printf("Old bootstrap checksum:     %#llx\n",
+                   (unsigned long long)le64toh(bb.bb_cksum));
+       }
+
+       bb.bb_secstart = bb.bb_secsize = bb.bb_flags = 0;
+
+       ALPHA_BOOT_BLOCK_CKSUM(&bb, &bb.bb_cksum);
+       if (params->flags & IB_SUNSUM)
+               sun_bootstrap(params, &bb);
+
+       printf("New bootstrap start sector: %llu\n",
+           (unsigned long long)le64toh(bb.bb_secstart));
+       printf("New bootstrap size:         %llu\n",
+           (unsigned long long)le64toh(bb.bb_secsize));
+       printf("New bootstrap checksum:     %#llx\n",
+           (unsigned long long)le64toh(bb.bb_cksum));
+
+       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), ALPHA_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);
+}
+
+static int
+alpha_setboot(ib_params *params)
+{
+       struct alpha_boot_block bb;
+       uint64_t                startblock;
+       int                     retval;
+       char                    *bootstrapbuf;
+       size_t                  bootstrapsize;
+       ssize_t                 rv;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(params->s1fd != -1);
+       assert(params->stage1 != NULL);
+       assert(sizeof(struct alpha_boot_block) == ALPHA_BOOT_BLOCK_BLOCKSIZE);
+
+       retval = 0;
+       bootstrapbuf = NULL;
+
+       /*
+        * Allocate a buffer, with space to round up the input file
+        * to the next block size boundary, and with space for the boot
+        * block.
+        */
+       bootstrapsize = roundup(params->s1stat.st_size,
+           ALPHA_BOOT_BLOCK_BLOCKSIZE);
+
+       bootstrapbuf = malloc(bootstrapsize);
+       if (bootstrapbuf == NULL) {
+               warn("Allocating %lu bytes", (unsigned long) bootstrapsize);
+               goto done;
+       }
+       memset(bootstrapbuf, 0, bootstrapsize);
+
+       /* read the file into the buffer */
+       rv = pread(params->s1fd, bootstrapbuf, params->s1stat.st_size, 0);
+       if (rv == -1) {
+               warn("Reading `%s'", params->stage1);
+               goto done;
+       } else if (rv != params->s1stat.st_size) {
+               warnx("Reading `%s': short read", params->stage1);
+               goto done;
+       }
+
+       rv = pread(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET);
+       if (rv == -1) {
+               warn("Reading `%s'", params->filesystem);
+               goto done;
+       } else if (rv != sizeof(bb)) {
+               warnx("Reading `%s': short read", params->filesystem);
+               goto done;
+       }
+
+       if (params->flags & IB_SUNSUM)
+               check_sparc(&bb, "Initial");
+
+               /* fill in the updated bootstrap fields */
+       if (params->flags & IB_APPEND) {
+               struct stat     filesyssb;
+
+               if (fstat(params->fsfd, &filesyssb) == -1) {
+                       warn("Examining `%s'", params->filesystem);
+                       goto done;
+               }
+               if (!S_ISREG(filesyssb.st_mode)) {
+                       warnx(
+                   "`%s' must be a regular file to append a bootstrap",
+                           params->filesystem);
+                       goto done;
+               }
+               startblock = howmany(filesyssb.st_size,
+                   ALPHA_BOOT_BLOCK_BLOCKSIZE);
+       } else if (params->flags & IB_STAGE1START) {
+               startblock = params->s1start;
+       } else {
+               startblock = ALPHA_BOOT_BLOCK_OFFSET /
+                   ALPHA_BOOT_BLOCK_BLOCKSIZE + 1;
+       }
+
+       bb.bb_secsize =
+           htole64(howmany(params->s1stat.st_size,
+               ALPHA_BOOT_BLOCK_BLOCKSIZE));
+       bb.bb_secstart = htole64(startblock);
+       bb.bb_flags = 0;
+
+       ALPHA_BOOT_BLOCK_CKSUM(&bb, &bb.bb_cksum);
+       if (params->flags & IB_SUNSUM)
+               sun_bootstrap(params, &bb);
+
+       if (params->flags & IB_VERBOSE) {
+               printf("Bootstrap start sector:  %llu\n",
+                   (unsigned long long)startblock);
+               printf("Bootstrap sector count:  %llu\n",
+                   (unsigned long long)le64toh(bb.bb_secsize));
+               printf("New boot block checksum: %#llx\n",
+                   (unsigned long long)le64toh(bb.bb_cksum));
+               printf("%sriting bootstrap\n",
+                   (params->flags & IB_NOWRITE) ? "Not w" : "W");
+       }
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+       rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize,
+            startblock * ALPHA_BOOT_BLOCK_BLOCKSIZE);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if ((size_t)rv != bootstrapsize) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       }
+
+       if (params->flags & IB_VERBOSE)
+               printf("Writing boot block\n");
+       rv = pwrite(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if (rv != sizeof(bb)) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       } else {
+               retval = 1;
+       }
+
+ done:
+       if (bootstrapbuf)
+               free(bootstrapbuf);
+       return (retval);
+}
+
+
+/*
+ * The Sun and alpha checksums overlay, and the Sun magic number also
+ * overlays the alpha checksum. If you think you are smart: stop here
+ * and do exercise one: figure out how to salt unimportant uint16_t
+ * words in mid-sector so that the alpha and sparc checksums match,
+ * and so the Sun magic number is embedded in the alpha checksum.
+ *
+ * The last uint64_t in the sector is the alpha arithmetic checksum.
+ * The last uint16_t in the sector is the sun xor checksum.
+ * The penultimate uint16_t in the sector is the sun magic number.
+ *
+ *     A:   511     510     509     508     507     506     505     504
+ *     S:   510     511     508     509     506     507     504     505
+ *     63     :       :       :     32:31     :       :       :       0
+ *     |      :       :       :      \:|      :       :       :       |
+ *     7654321076543210765432107654321076543210765432107654321076543210
+ *     |--  sparc   --||--  sparc   --|
+ *     |-- checksum --||--  magic   --|
+ *     |----------------------- alpha checksum -----------------------|
+ *                     1011111011011010
+ *                        b   e   d   a
+ */
+
+static void
+resum(ib_params *params, struct alpha_boot_block * const bb, uint16_t *bb16)
+{
+       static uint64_t lastsum;
+
+       if (bb16 != NULL)
+               memcpy(bb, bb16, sizeof(*bb));
+       ALPHA_BOOT_BLOCK_CKSUM(bb, &bb->bb_cksum);
+       if (bb16 != NULL)
+               memcpy(bb16, bb, sizeof(*bb));
+       if ((params->flags & IB_VERBOSE) && lastsum != bb->bb_cksum)
+               printf("alpha checksum now %016llx\n",
+                   (unsigned long long)le64toh(bb->bb_cksum));
+       lastsum = bb->bb_cksum;
+}
+
+static void
+sun_bootstrap(ib_params *params, struct alpha_boot_block * const bb)
+{
+#      define BB_ADJUST_OFFSET 64
+       static char our_int16s[] = "\2\3\6\7\12";
+       uint16_t i, j, chkdelta, sunsum, bb16[256];
+
+       /*
+        * Theory: the alpha checksum is adjusted so bits 47:32 add up
+        * to the Sun magic number. Then, another adjustment is computed
+        * so bits 63:48 add up to the Sun checksum, and applied in pieces
+        * so it changes the alpha checksum but not the Sun value.
+        *
+        * Note: using memcpy(3) instead of a union as a strict c89/c9x
+        * conformance experiment and to avoid a public interface delta.
+        */
+       assert(sizeof(bb16) == sizeof(*bb));
+       memcpy(bb16, bb, sizeof(bb16));
+       for (i = 0; our_int16s[i]; ++i) {
+               j = BB_ADJUST_OFFSET + our_int16s[i];
+               if (bb16[j]) {
+                       warnx("Non-zero bits %04x in bytes %d..%d",
+                           bb16[j], j * 2, j * 2 + 1);
+                       bb16[j] = 0;
+                       resum(params, bb, bb16);
+               }
+       }
+       /*
+        * Make alpha checksum <47:32> come out to the sun magic.
+        */
+       bb16[BB_ADJUST_OFFSET + 2] = htobe16(SUN_DKMAGIC) - bb16[254];
+       resum(params, bb, bb16);
+       sunsum = compute_sunsum(bb16);          /* might be the final value */
+       if (params->flags & IB_VERBOSE)
+               printf("target sun checksum is %04x\n", sunsum);
+       /*
+        * Arrange to have alpha 63:48 add up to the sparc checksum.
+        */
+       chkdelta = sunsum - bb16[255];
+       bb16[BB_ADJUST_OFFSET + 3] = chkdelta >> 1;
+       bb16[BB_ADJUST_OFFSET + 7] = chkdelta >> 1;
+       /*
+        * By placing half the correction in two different uint64_t words at
+        * positions 63:48, the sparc sum will not change but the alpha sum
+        * will have the full correction, but only if the target adjustment
+        * was even. If it was odd, reverse propagate the carry one place.
+        */
+       if (chkdelta & 1) {
+               if (params->flags & IB_VERBOSE)
+                       printf("target adjustment %04x was odd, correcting\n",
+                           chkdelta);
+               assert(bb16[BB_ADJUST_OFFSET + 6] == 0);
+               assert(bb16[BB_ADJUST_OFFSET + 012] == 0);
+               bb16[BB_ADJUST_OFFSET + 6] += 0x8000;
+               bb16[BB_ADJUST_OFFSET + 012] += 0x8000;
+       }
+       resum(params, bb, bb16);
+       if (params->flags & IB_VERBOSE)
+               printf("final harmonized checksum: %016llx\n",
+                   (unsigned long long)le64toh(bb->bb_cksum));
+       check_sparc(bb, "Final");
+}
+
+static void
+check_sparc(const struct alpha_boot_block * const bb, const char *when)
+{
+       uint16_t bb16[256];
+#define wmsg "%s sparc %s 0x%04x invalid, expected 0x%04x"
+
+       memcpy(bb16, bb, sizeof(bb16));
+       if (compute_sunsum(bb16) != bb16[255])
+               warnx(wmsg, when, "checksum", bb16[255], compute_sunsum(bb16));
+       if (bb16[254] != htobe16(SUN_DKMAGIC))
+               warnx(wmsg, when, "magic number", bb16[254],
+                   htobe16(SUN_DKMAGIC));
+}
diff --git a/usr.sbin/installboot/arch/amiga.c b/usr.sbin/installboot/arch/amiga.c
new file mode 100644 (file)
index 0000000..e6650b9
--- /dev/null
@@ -0,0 +1,173 @@
+/*     $NetBSD: amiga.c,v 1.7 2010/01/14 16:27:49 tsutsui Exp $        */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Michael Hitch.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: amiga.c,v 1.7 2010/01/14 16:27:49 tsutsui Exp $");
+#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 <unistd.h>
+#include <string.h>
+
+#include "installboot.h"
+
+/* XXX Must be kept in sync with bbstart.s! */
+#define CMDLN_LOC 0x10
+#define CMDLN_LEN 0x20
+
+#define CHKSUMOFFS 1
+
+u_int32_t chksum(u_int32_t *, int);
+
+static int amiga_setboot(ib_params *);
+
+struct ib_mach ib_mach_amiga =
+       { "amiga", amiga_setboot, no_clearboot, no_editboot,
+               IB_STAGE1START | IB_STAGE2START | IB_COMMAND };
+
+static int
+amiga_setboot(ib_params *params)
+{
+       int retval;
+       ssize_t                 rv;
+       char *dline;
+       int sumlen;
+       u_int32_t sum2, sum16;
+       
+       struct stat             bootstrapsb;
+
+       u_int32_t block[128*16];
+
+       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;
+       }
+
+       rv = pread(params->s1fd, &block, sizeof(block), 0);
+       if (rv == -1) {
+               warn("Reading `%s'", params->stage1);
+               goto done;
+       } else if (rv != sizeof(block)) {
+               warnx("Reading `%s': short read", params->stage1);
+               goto done;
+       }
+
+       /* XXX the choices should not be hardcoded */
+
+       sum2  = chksum(block, 1024/4);
+       sum16 = chksum(block, 8192/4);
+
+       if (sum16 == 0xffffffff) {
+               sumlen = 8192/4;
+       } else if (sum2 == 0xffffffff) {
+               sumlen = 1024/4;
+       } else {
+               errx(1, "%s: wrong checksum", params->stage1);
+               /* NOTREACHED */
+       }
+
+       if (sum2 == sum16) {
+               warnx("eek - both sums are the same");
+       }
+
+       if (params->flags & IB_COMMAND) {
+               dline = (char *)&(block[CMDLN_LOC/4]);
+               /* XXX keep the default default line in sync with bbstart.s */
+               if (strcmp(dline, "netbsd -ASn2") != 0) {
+                       errx(1, "Old bootblock version? Can't change command line.");
+               }
+               (void)strncpy(dline, params->command, CMDLN_LEN-1);
+
+               block[1] = 0;
+               block[1] = 0xffffffff - chksum(block, sumlen);
+       }
+
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+
+       if (params->flags & IB_VERBOSE)
+               printf("Writing boot block\n");
+       rv = pwrite(params->fsfd, &block, sizeof(block), 0);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if (rv != sizeof(block)) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       } else {
+               retval = 1;
+       }
+
+ done:
+       return (retval);
+}
+
+u_int32_t
+chksum(block, size)
+       u_int32_t *block;
+       int size;
+{
+       u_int32_t sum, lastsum;
+       int i;
+
+       sum = 0;
+
+       for (i=0; i<size; i++) {
+               lastsum = sum;
+               sum += htobe32(block[i]);
+               if (sum < lastsum)
+                       ++sum;
+       }
+
+       return sum;
+}
diff --git a/usr.sbin/installboot/arch/emips.c b/usr.sbin/installboot/arch/emips.c
new file mode 100644 (file)
index 0000000..a1e2e2e
--- /dev/null
@@ -0,0 +1,145 @@
+/*     $NetBSD: emips.c,v 1.1 2011/01/26 01:18:55 pooka Exp $  */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Simon Burge.
+ *
+ * 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) 1999 Ross Harvey.  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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Ross Harvey
+ *     for the NetBSD Project.
+ * 4. 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) 1999 Christopher G. Demetriou.  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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Christopher G. Demetriou
+ *     for the NetBSD Project.
+ * 4. 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(__lint)
+__RCSID("$NetBSD: emips.c,v 1.1 2011/01/26 01:18:55 pooka Exp $");
+#endif /* !__lint */
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/exec_elf.h>
+
+#include "installboot.h"
+
+static int emips_clearboot(ib_params *);
+static int emips_setboot(ib_params *);
+
+struct ib_mach ib_mach_emips =
+       { "emips", emips_setboot, emips_clearboot, no_editboot,
+               IB_STAGE1START | IB_APPEND | IB_SUNSUM };
+
+
+static int
+emips_clearboot(ib_params *params)
+{
+       /* Nothing to do */
+       return (1);
+}
+
+static int
+emips_setboot(ib_params *params)
+{
+       /* Nothing to do */
+       return (1);
+}
diff --git a/usr.sbin/installboot/arch/ews4800mips.c b/usr.sbin/installboot/arch/ews4800mips.c
new file mode 100644 (file)
index 0000000..3a8e5d0
--- /dev/null
@@ -0,0 +1,62 @@
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: ews4800mips.c,v 1.2 2006/02/18 10:08:07 dsl Exp $");
+#endif /* !__lint */
+
+#include <sys/param.h>
+#include <unistd.h>
+#include <err.h>
+#include <stdio.h>
+#include "installboot.h"
+
+static int ews4800mips_setboot(ib_params *);
+
+struct ib_mach ib_mach_ews4800mips =
+       { "ews4800mips", ews4800mips_setboot, no_clearboot, no_editboot, 0};
+
+struct bbinfo_params ews4800mips_bbparams = {
+       EWS4800MIPS_BBINFO_MAGIC,
+       EWS4800MIPS_BOOT_BLOCK_OFFSET,
+       EWS4800MIPS_BOOT_BLOCK_BLOCKSIZE,
+       EWS4800MIPS_BOOT_BLOCK_MAX_SIZE,
+       0,
+       BBINFO_BIG_ENDIAN,
+};
+
+static int
+ews4800mips_setboot(ib_params *params)
+{
+       u_int8_t buf[EWS4800MIPS_BOOT_BLOCK_MAX_SIZE];
+       int rv;
+
+       rv = pread(params->s1fd, buf, sizeof buf, 0);
+       if (rv == -1) {
+               warn("Reading `%s'", params->stage1);
+               return 0;
+       } else if (rv != sizeof buf) {
+               warnx("Reading `%s' : short read", params->stage1);
+               return 0;
+       }
+
+       if (params->flags & IB_NOWRITE)
+               return 1;
+
+       if (params->flags & IB_VERBOSE)
+               printf("Writing boot block\n");
+
+       rv = pwrite(params->fsfd, buf, sizeof buf, 0);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               return 0;
+       } else if (rv != sizeof buf) {
+               warnx("Writing `%s': short write", params->filesystem);
+               return 0;
+       }
+
+       return 1;
+}
diff --git a/usr.sbin/installboot/arch/hp300.c b/usr.sbin/installboot/arch/hp300.c
new file mode 100644 (file)
index 0000000..57410fc
--- /dev/null
@@ -0,0 +1,214 @@
+/* $NetBSD: hp300.c,v 1.13 2011/02/10 23:25:11 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by David Laight.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: hp300.c,v 1.13 2011/02/10 23:25:11 tsutsui Exp $");
+#endif /* !__lint */
+
+/* We need the target disklabel.h, not the hosts one..... */
+#ifdef HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#include <nbinclude/sys/disklabel.h>
+#else                                                                          
+#include <sys/disklabel.h>
+#endif
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+
+#include <assert.h>
+#include <err.h>
+#include <md5.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "installboot.h"
+
+static int hp300_setboot(ib_params *);
+
+struct ib_mach ib_mach_hp300 =
+       { "hp300", hp300_setboot, no_clearboot, no_editboot, IB_APPEND };
+
+static int
+hp300_setboot(ib_params *params)
+{
+       int             retval;
+       uint8_t         *bootstrap;
+       ssize_t         rv;
+       struct partition *boot;
+       struct hp300_lifdir *lifdir;
+       int             offset;
+       int             i;
+       unsigned int    secsize = HP300_SECTSIZE;
+       uint64_t        boot_size, boot_offset;
+       struct disklabel *label;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(params->s1fd != -1);
+       assert(params->stage1 != NULL);
+
+       retval = 0;
+       bootstrap = MAP_FAILED;
+
+       label = malloc(params->sectorsize);
+       if (label == NULL) {
+               warn("Failed to allocate memory for disklabel");
+               goto done;
+       }
+
+       if (params->flags & IB_APPEND) {
+               if (!S_ISREG(params->fsstat.st_mode)) {
+                       warnx(
+                   "`%s' must be a regular file to append a bootstrap",
+                           params->filesystem);
+                       goto done;
+               }
+               boot_offset = roundup(params->fsstat.st_size, HP300_SECTSIZE);
+       } else {
+               /*
+                * The bootstrap can be well over 8k, and must go into a BOOT
+                * partition. Read NetBSD label to locate BOOT partition.
+                */
+               if (pread(params->fsfd, label, params->sectorsize,
+                   LABELSECTOR * params->sectorsize)
+                   != (ssize_t)params->sectorsize) {
+                       warn("reading disklabel");
+                       goto done;
+               }
+               /* And a quick validation - must be a big-endian label */
+               secsize = be32toh(label->d_secsize);
+               if (label->d_magic != htobe32(DISKMAGIC) ||
+                   label->d_magic2 != htobe32(DISKMAGIC) ||
+                   secsize == 0 || secsize & (secsize - 1) ||
+                   be16toh(label->d_npartitions) > MAXMAXPARTITIONS) {
+                       warnx("Invalid disklabel in %s", params->filesystem);
+                       goto done;
+               }
+
+               i = be16toh(label->d_npartitions);
+               for (boot = label->d_partitions; ; boot++) {
+                       if (--i < 0) {
+                               warnx("No BOOT partition");
+                               goto done;
+                       }
+                       if (boot->p_fstype == FS_BOOT)
+                               break;
+               }
+               boot_size = be32toh(boot->p_size) * (uint64_t)secsize;
+               boot_offset = be32toh(boot->p_offset) * (uint64_t)secsize;
+
+               /*
+                * We put the entire LIF file into the BOOT partition even when
+                * it doesn't start at the beginning of the disk.
+                *
+                * Maybe we ought to be able to take a binary file and add
+                * it to the LIF filesystem.
+                */
+               if (boot_size < (uint64_t)params->s1stat.st_size) {
+                       warn("BOOT partition too small (%llu < %llu)",
+                               (unsigned long long)boot_size,
+                               (unsigned long long)params->s1stat.st_size);
+                       goto done;
+               }
+       }
+
+       bootstrap = mmap(NULL, params->s1stat.st_size, PROT_READ | PROT_WRITE,
+                           MAP_PRIVATE, params->s1fd, 0);
+       if (bootstrap == MAP_FAILED) {
+               warn("mmaping `%s'", params->stage1);
+               goto done;
+       }
+
+       /* Relocate files, sanity check LIF directory on the way */
+       lifdir = (void *)(bootstrap + HP300_SECTSIZE * 2);
+       for (i = 0; i < 8; lifdir++, i++) {
+               int32_t addr = be32toh(lifdir->dir_addr);
+               int32_t limit = (params->s1stat.st_size - 1) / HP300_SECTSIZE + 1;
+               int32_t end = addr + be32toh(lifdir->dir_length);
+               if (end > limit) {
+                       warnx("LIF entry %d larger (%d %d) than LIF file",
+                               i, end, limit);
+                       goto done;
+               }
+               if (addr != 0 && boot_offset != 0)
+                       lifdir->dir_addr = htobe32(addr + boot_offset
+                                                           / HP300_SECTSIZE);
+       }
+
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+
+       /* Write LIF volume header and directory to sectors 0 and 1 */
+       rv = pwrite(params->fsfd, bootstrap, 1024, 0);
+       if (rv != 1024) {
+               if (rv == -1)
+                       warn("Writing `%s'", params->filesystem);
+               else
+                       warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       }
+
+       /* Write files to BOOT partition */
+       offset = boot_offset <= HP300_SECTSIZE * 16 ? HP300_SECTSIZE * 16 : 0;
+       i = roundup(params->s1stat.st_size, secsize) - offset;
+       rv = pwrite(params->fsfd, bootstrap + offset, i, boot_offset + offset);
+       if (rv != i) {
+               if (rv == -1)
+                       warn("Writing boot filesystem of `%s'",
+                               params->filesystem);
+               else
+                       warnx("Writing boot filesystem of `%s': short write",
+                               params->filesystem);
+               goto done;
+       }
+
+       retval = 1;
+
+ done:
+       if (label != NULL)
+               free(label);
+       if (bootstrap != MAP_FAILED)
+               munmap(bootstrap, params->s1stat.st_size);
+       return retval;
+}
diff --git a/usr.sbin/installboot/arch/hp700.c b/usr.sbin/installboot/arch/hp700.c
new file mode 100644 (file)
index 0000000..c6d8480
--- /dev/null
@@ -0,0 +1,220 @@
+/*     $NetBSD: hp700.c,v 1.4 2008/04/28 20:24:16 martin Exp $ */
+
+/*-
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: hp700.c,v 1.4 2008/04/28 20:24:16 martin Exp $");
+#endif /* !__lint */
+
+/* We need the target disklabel.h, not the hosts one..... */
+#ifdef HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#include <nbinclude/sys/disklabel.h>
+#else                                                                          
+#include <sys/disklabel.h>
+#endif
+#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"
+
+#define HP700_LABELOFFSET      512
+#define HP700_LABELSIZE                404 /* reserve 16 partitions */
+#define        HP700_BOOT_BLOCK_SIZE   8192
+
+static int hp700_clearboot(ib_params *);
+static int hp700_setboot(ib_params *);
+
+struct ib_mach ib_mach_hp700 =
+       { "hp700", hp700_setboot, hp700_clearboot, no_editboot, 0};
+
+static int
+hp700_clearboot(ib_params *params)
+{
+       char            bb[HP700_BOOT_BLOCK_SIZE];
+       int             retval, eol;
+       ssize_t         rv;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+
+       retval = 0;
+
+       /* read disklabel on the target disk */
+       rv = pread(params->fsfd, bb, sizeof bb, 0);
+       if (rv == -1) {
+               warn("Reading `%s'", params->filesystem);
+               goto done;
+       } else if (rv != sizeof bb) {
+               warnx("Reading `%s': short read", params->filesystem);
+               goto done;
+       }
+
+       /* clear header */
+       memset(bb, 0, HP700_LABELOFFSET);
+       eol = HP700_LABELOFFSET + HP700_LABELSIZE;
+       memset(&bb[eol], 0, sizeof bb - eol);
+
+       if (params->flags & IB_VERBOSE) {
+               printf("%slearing bootstrap\n",
+                   (params->flags & IB_NOWRITE) ? "Not c" : "C");
+       }
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+
+       rv = pwrite(params->fsfd, bb, sizeof bb, 0);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if (rv != HP700_BOOT_BLOCK_SIZE) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       } else
+               retval = 1;
+
+ done:
+       return (retval);
+}
+
+static int
+hp700_setboot(ib_params *params)
+{
+       struct stat     bootstrapsb;
+       char            bb[HP700_BOOT_BLOCK_SIZE];
+       struct {
+               char    l_off[HP700_LABELOFFSET];
+               struct disklabel l;
+               char    l_pad[HP700_BOOT_BLOCK_SIZE
+                           - HP700_LABELOFFSET - sizeof(struct disklabel)];
+       } label;
+       unsigned int    secsize, npart;
+       int             retval;
+       ssize_t         rv;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(params->s1fd != -1);
+       assert(params->stage1 != NULL);
+
+       retval = 0;
+
+       /* read disklabel on the target disk */
+       rv = pread(params->fsfd, &label, HP700_BOOT_BLOCK_SIZE, 0);
+       if (rv == -1) {
+               warn("Reading `%s'", params->filesystem);
+               goto done;
+       } else if (rv != HP700_BOOT_BLOCK_SIZE) {
+               warnx("Reading `%s': short read", params->filesystem);
+               goto done;
+       }
+
+       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;
+       }
+
+       /* check if valid disklabel exists */
+       secsize = be32toh(label.l.d_secsize);
+       npart = be16toh(label.l.d_npartitions);
+       if (label.l.d_magic != htobe32(DISKMAGIC) ||
+           label.l.d_magic2 != htobe32(DISKMAGIC) ||
+           secsize == 0 || secsize & (secsize - 1) ||
+           npart > MAXMAXPARTITIONS) {
+               warnx("No disklabel in `%s'", params->filesystem);
+
+       /* then check if boot partition exists */
+       } else if (npart < 1 || label.l.d_partitions[0].p_size == 0) {
+               warnx("Partition `a' doesn't exist in %s", params->filesystem);
+
+       /* check if the boot partition is below 2GB */
+       } else if (be32toh(label.l.d_partitions[0].p_offset) +
+           be32toh(label.l.d_partitions[0].p_size) >
+           ((unsigned)2*1024*1024*1024) / secsize) {
+               warnx("WARNING: Partition `a' of `%s' exceeds 2GB boundary.",
+                   params->filesystem);
+               warnx("WARNING: It won't boot since hp700 PDC can handle only 2GB.");
+       }
+
+       /* read boot loader */
+       memset(&bb, 0, sizeof bb);
+       rv = read(params->s1fd, &bb, sizeof bb);
+       if (rv == -1) {
+               warn("Reading `%s'", params->stage1);
+               goto done;
+       }
+       /* then, overwrite disklabel */
+       memcpy(&bb[HP700_LABELOFFSET], &label.l, HP700_LABELSIZE);
+
+       if (params->flags & IB_VERBOSE) {
+               printf("Bootstrap start sector: %#x\n", 0);
+               printf("Bootstrap byte count:   %#zx\n", rv);
+               printf("%sriting bootstrap\n",
+                   (params->flags & IB_NOWRITE) ? "Not w" : "W");
+       }
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+
+       /* write boot loader and disklabel into the target disk */
+       rv = pwrite(params->fsfd, &bb, HP700_BOOT_BLOCK_SIZE, 0);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if (rv != HP700_BOOT_BLOCK_SIZE) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       } else
+               retval = 1;
+
+ done:
+       return (retval);
+}
diff --git a/usr.sbin/installboot/arch/i386.c b/usr.sbin/installboot/arch/i386.c
new file mode 100644 (file)
index 0000000..64a6b0d
--- /dev/null
@@ -0,0 +1,552 @@
+/* $NetBSD: i386.c,v 1.37 2011/08/14 17:50:17 christos Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by David Laight.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: i386.c,v 1.37 2011/08/14 17:50:17 christos Exp $");
+#endif /* !__lint */
+
+#include <sys/param.h>
+#ifndef HAVE_NBTOOL_CONFIG_H
+#include <sys/ioctl.h>
+#include <sys/dkio.h>
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <err.h>
+#include <md5.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "installboot.h"
+
+static const struct console_name {
+       const char      *name;          /* Name of console selection */
+       const int       dev;            /* value matching CONSDEV_* from sys/arch/i386/stand/lib/libi386.h */
+} consoles[] = {
+       { "pc",         0 /* CONSDEV_PC */ },
+       { "com0",       1 /* CONSDEV_COM0 */ },
+       { "com1",       2 /* CONSDEV_COM1 */ },
+       { "com2",       3 /* CONSDEV_COM2 */ },
+       { "com3",       4 /* CONSDEV_COM3 */ },
+       { "com0kbd",    5 /* CONSDEV_COM0KBD */ },
+       { "com1kbd",    6 /* CONSDEV_COM1KBD */ },
+       { "com2kbd",    7 /* CONSDEV_COM2KBD */ },
+       { "com3kbd",    8 /* CONSDEV_COM3KBD */ },
+       { "auto",       -1 /* CONSDEV_AUTO */ },
+};
+
+static int i386_setboot(ib_params *);
+static int i386_editboot(ib_params *);
+
+struct ib_mach ib_mach_i386 =
+       { "i386", i386_setboot, no_clearboot, i386_editboot,
+               IB_RESETVIDEO | IB_CONSOLE | IB_CONSPEED | IB_CONSADDR |
+               IB_KEYMAP | IB_PASSWORD | IB_TIMEOUT |
+               IB_MODULES | IB_BOOTCONF };
+
+struct ib_mach ib_mach_amd64 =
+       { "amd64", i386_setboot, no_clearboot, i386_editboot,
+               IB_RESETVIDEO | IB_CONSOLE | IB_CONSPEED | IB_CONSADDR |
+               IB_KEYMAP | IB_PASSWORD | IB_TIMEOUT |
+               IB_MODULES | IB_BOOTCONF };
+
+/*
+ * Attempting to write the 'labelsector' (or a sector near it - within 8k?)
+ * using the non-raw disk device fails silently.  This can be detected (today)
+ * by doing a fsync() and a read back.
+ * This is very likely to affect installboot, indeed the code may need to
+ * be written into the 'labelsector' itself - especially on non-512 byte media.
+ * We do all writes with a read verify.
+ * If EROFS is returned we also try to enable writes to the label sector.
+ * (Maybe these functions should be in the generic part of installboot.)
+ */
+static int
+pwrite_validate(int fd, const void *buf, size_t n_bytes, off_t offset)
+{
+       void *r_buf;
+       ssize_t rv;
+
+       r_buf = malloc(n_bytes);
+       if (r_buf == NULL)
+               return -1;
+       rv = pwrite(fd, buf, n_bytes, offset);
+       if (rv == -1) {
+               free(r_buf);
+               return -1;
+       }
+       fsync(fd);
+       if (pread(fd, r_buf, rv, offset) == rv && memcmp(r_buf, buf, rv) == 0) {
+               free(r_buf);
+               return rv;
+       }
+       free(r_buf);
+       errno = EROFS;
+       return -1;
+}
+
+static int
+write_boot_area(ib_params *params, uint8_t *buf, size_t len)
+{
+       int rv, i;
+
+       /*
+        * Writing the 'label' sector (likely to be bytes 512-1023) could
+        * fail, so we try to avoid writing that area.
+        * Unfortunately, if we are accessing the raw disk, and the sector
+        * size is larger than 512 bytes that is also doomed.
+        * See how we get on....
+        *
+        * NB: Even if the physical sector size is not 512, the space for
+        * the label is 512 bytes from the start of the disk.
+        * So all the '512' constants in these functions are correct.
+        */
+
+       /* Write out first 512 bytes - the pbr code */
+       rv = pwrite_validate(params->fsfd, buf, 512, 0);
+       if (rv == 512) {
+               /* That worked, do the rest */
+               if (len == 512)
+                       return 1;
+               len -= 512 * 2;
+               rv = pwrite_validate(params->fsfd, buf + 512 * 2, len, 512 * 2);
+               if (rv != (ssize_t)len)
+                       goto bad_write;
+               return 1;
+       }
+       if (rv != -1 || (errno != EINVAL && errno != EROFS))
+               goto bad_write;
+
+       if (errno == EINVAL) {
+               /* Assume the failure was due to to the sector size > 512 */
+               rv = pwrite_validate(params->fsfd, buf, len, 0);
+               if (rv == (ssize_t)len)
+                       return 1;
+               if (rv != -1 || (errno != EROFS))
+                       goto bad_write;
+       }
+
+#ifdef DIOCWLABEL
+       /* Pesky label is protected, try to unprotect it */
+       i = 1;
+       rv = ioctl(params->fsfd, DIOCWLABEL, &i);
+       if (rv != 0) {
+               warn("Cannot enable writes to the label sector");
+               return 0;
+       }
+       /* Try again with label write-enabled */
+       rv = pwrite_validate(params->fsfd, buf, len, 0);
+
+       /* Reset write-protext */
+       i = 0;
+       ioctl(params->fsfd, DIOCWLABEL, &i);
+       if (rv == (ssize_t)len)
+               return 1;
+#endif
+
+  bad_write:
+       if (rv == -1)
+               warn("Writing `%s'", params->filesystem);
+       else 
+               warnx("Writing `%s': short write, %u bytes",
+                       params->filesystem, rv);
+       return 0;
+}
+
+static void
+show_i386_boot_params(struct x86_boot_params  *bpp)
+{
+       size_t i;
+
+       printf("Boot options:        ");
+       printf("timeout %d, ", le32toh(bpp->bp_timeout));
+       printf("flags %x, ", le32toh(bpp->bp_flags));
+       printf("speed %d, ", le32toh(bpp->bp_conspeed));
+       printf("ioaddr %x, ", le32toh(bpp->bp_consaddr));
+       for (i = 0; i < __arraycount(consoles); i++) {
+               if (consoles[i].dev == (int)le32toh(bpp->bp_consdev))
+                       break;
+       }
+       if (i == __arraycount(consoles))
+               printf("console %d\n", le32toh(bpp->bp_consdev));
+       else
+               printf("console %s\n", consoles[i].name);
+       if (bpp->bp_keymap[0])
+               printf("                     keymap %s\n", bpp->bp_keymap);
+}
+
+static int
+is_zero(const uint8_t *p, unsigned int len)
+{
+       return len == 0 || (p[0] == 0 && memcmp(p, p + 1, len - 1) == 0);
+}
+
+static int
+update_i386_boot_params(ib_params *params, struct x86_boot_params  *bpp)
+{
+       struct x86_boot_params bp;
+       uint32_t bplen;
+       size_t i;
+
+       bplen = le32toh(bpp->bp_length);
+       if (bplen > sizeof bp)
+               /* Ignore pad space in bootxx */
+               bplen = sizeof bp;
+
+       /* Take (and update) local copy so we handle size mismatches */
+       memset(&bp, 0, sizeof bp);
+       memcpy(&bp, bpp, bplen);
+
+       if (params->flags & IB_TIMEOUT)
+               bp.bp_timeout = htole32(params->timeout);
+       if (params->flags & IB_RESETVIDEO)
+               bp.bp_flags ^= htole32(X86_BP_FLAGS_RESET_VIDEO);
+       if (params->flags & IB_CONSPEED)
+               bp.bp_conspeed = htole32(params->conspeed);
+       if (params->flags & IB_CONSADDR)
+               bp.bp_consaddr = htole32(params->consaddr);
+       if (params->flags & IB_CONSOLE) {
+               for (i = 0; i < __arraycount(consoles); i++)
+                       if (strcmp(consoles[i].name, params->console) == 0)
+                               break;
+
+               if (i == __arraycount(consoles)) {
+                       warnx("invalid console name, valid names are:");
+                       (void)fprintf(stderr, "\t%s", consoles[0].name);
+                       for (i = 1; consoles[i].name != NULL; i++)
+                               (void)fprintf(stderr, ", %s", consoles[i].name);
+                       (void)fprintf(stderr, "\n");
+                       return 1;
+               }
+               bp.bp_consdev = htole32(consoles[i].dev);
+       }
+       if (params->flags & IB_PASSWORD) {
+               if (params->password[0]) {
+                       MD5_CTX md5ctx;
+                       MD5Init(&md5ctx);
+                       MD5Update(&md5ctx, params->password,
+                           strlen(params->password));
+                       MD5Final(bp.bp_password, &md5ctx);
+                       bp.bp_flags |= htole32(X86_BP_FLAGS_PASSWORD);
+               } else {
+                       memset(&bp.bp_password, 0, sizeof bp.bp_password);
+                       bp.bp_flags &= ~htole32(X86_BP_FLAGS_PASSWORD);
+               }
+       }
+       if (params->flags & IB_KEYMAP)
+               strlcpy(bp.bp_keymap, params->keymap, sizeof bp.bp_keymap);
+       if (params->flags & IB_MODULES)
+               bp.bp_flags ^= htole32(X86_BP_FLAGS_NOMODULES);
+       if (params->flags & IB_BOOTCONF)
+               bp.bp_flags ^= htole32(X86_BP_FLAGS_NOBOOTCONF);
+
+       if (params->flags & (IB_NOWRITE | IB_VERBOSE))
+               show_i386_boot_params(&bp);
+
+       /* Check we aren't trying to set anything we can't save */
+       if (!is_zero((char *)&bp + bplen, sizeof bp - bplen)) {
+               warnx("Patch area in stage1 bootstrap is too small");
+               return 1;
+       }
+       memcpy(bpp, &bp, bplen);
+       return 0;
+}
+
+static int
+i386_setboot(ib_params *params)
+{
+       unsigned int    u;
+       ssize_t         rv;
+       uint32_t        *magic, expected_magic;
+       union {
+           struct mbr_sector   mbr;
+           uint8_t             b[8192];
+       } disk_buf, bootstrap;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(params->s1fd != -1);
+       assert(params->stage1 != NULL);
+
+       /*
+        * There is only 8k of space in a FFSv1 partition (and ustarfs)
+        * so ensure we don't splat over anything important.
+        */
+       if (params->s1stat.st_size > (off_t)(sizeof bootstrap)) {
+               warnx("stage1 bootstrap `%s' (%u bytes) is larger than 8192 bytes",
+                       params->stage1, (unsigned int)params->s1stat.st_size);
+               return 0;
+       }
+       if (params->s1stat.st_size < 3 * 512 && params->s1stat.st_size != 512) {
+               warnx("stage1 bootstrap `%s' (%u bytes) is too small",
+                       params->stage1, (unsigned int)params->s1stat.st_size);
+               return 0;
+       }
+
+       /* Read in the existing disk header and boot code */
+       rv = pread(params->fsfd, &disk_buf, sizeof (disk_buf), 0);
+       if (rv != sizeof(disk_buf)) {
+               if (rv == -1)
+                       warn("Reading `%s'", params->filesystem);
+               else
+                       warnx("Reading `%s': short read, %ld bytes"
+                           " (should be %ld)", params->filesystem, (long)rv,
+                           (long)sizeof(disk_buf));
+               return 0;
+       }
+
+       if (disk_buf.mbr.mbr_magic != le16toh(MBR_MAGIC)) {
+               if (params->flags & IB_VERBOSE) {
+                       printf(
+                   "Ignoring PBR with invalid magic in sector 0 of `%s'\n",
+                           params->filesystem);
+               }
+               memset(&disk_buf, 0, 512);
+       }
+
+       /* Read the new bootstrap code. */
+       rv = pread(params->s1fd, &bootstrap, params->s1stat.st_size, 0);
+       if (rv != params->s1stat.st_size) {
+               if (rv == -1)
+                       warn("Reading `%s'", params->stage1);
+               else
+                       warnx("Reading `%s': short read, %ld bytes"
+                           " (should be %ld)", params->stage1, (long)rv,
+                           (long)params->s1stat.st_size);
+               return 0;
+       }
+
+       /*
+        * The bootstrap code is either 512 bytes for booting FAT16, or best
+        * part of 8k (with bytes 512-1023 all zeros).
+        */
+       if (params->s1stat.st_size == 512) {
+               /* Magic number is at end of pbr code */
+               magic = (void *)(bootstrap.b + 512 - 16 + 4);
+               expected_magic = htole32(X86_BOOT_MAGIC_FAT);
+       } else {
+               /* Magic number is at start of sector following label */
+               magic = (void *)(bootstrap.b + 512 * 2 + 4);
+               expected_magic = htole32(X86_BOOT_MAGIC_1);
+               /*
+                * For a variety of reasons we restrict our 'normal' partition
+                * boot code to a size which enable it to be used as mbr code.
+                * IMHO this is bugus (dsl).
+                */
+               if (!is_zero(bootstrap.b + 512-2-64, 64)) {
+                       warnx("Data in mbr partition table of new bootstrap");
+                       return 0;
+               }
+               if (!is_zero(bootstrap.b + 512, 512)) {
+                       warnx("Data in label part of new bootstrap");
+                       return 0;
+               }
+               /* Copy mbr table and label from existing disk buffer */
+               memcpy(bootstrap.b + 512-2-64, disk_buf.b + 512-2-64, 64);
+               memcpy(bootstrap.b + 512, disk_buf.b + 512, 512);
+       }
+
+       /* Validate the 'magic number' that marks the parameter block */
+       if (*magic != expected_magic) {
+               warnx("Invalid magic in stage1 bootstrap %x != %x",
+                               *magic, expected_magic);
+               return 0;
+       }
+
+       /*
+        * If the partition has a FAT (or NTFS) filesystem, then we must
+        * preserve the BIOS Parameter Block (BPB).
+        * It is also very likely that there isn't 8k of space available
+        * for (say) bootxx_msdos, and that blindly installing it will trash
+        * the FAT filesystem.
+        * To avoid this we check the number of 'reserved' sectors to ensure
+        * there there is enough space.
+        * Unfortunately newfs(8) doesn't (yet) splat the BPB (which is
+        * effectively the FAT superblock) when a filesystem is initailised
+        * so this code tends to complain rather too often,
+        * Specifying 'installboot -f' will delete the old BPB info.
+        */
+       if (!(params->flags & IB_FORCE)) {
+               #define USE_F ", use -f (may invalidate filesystem)"
+               /*
+                * For FAT compatibility, the pbr code starts 'jmp xx; nop'
+                * followed by the BIOS Parameter Block (BPB).
+                * The 2nd byte (jump offset) is the size of the nop + BPB.
+                */
+               if (bootstrap.b[0] != 0xeb || bootstrap.b[2] != 0x90) {
+                       warnx("No BPB in new bootstrap %02x:%02x:%02x" USE_F,
+                               bootstrap.b[0], bootstrap.b[1], bootstrap.b[2]);
+                       return 0;
+               }
+
+               /* Find size of old BPB, and copy into new bootcode */
+               if (!is_zero(disk_buf.b + 3 + 8, disk_buf.b[1] - 1 - 8)) {
+                       struct mbr_bpbFAT16 *bpb = (void *)(disk_buf.b + 3 + 8);
+                       /* Check enough space before the FAT for the bootcode */
+                       u = le16toh(bpb->bpbBytesPerSec)
+                           * le16toh(bpb->bpbResSectors);
+                       if (u != 0 && u < params->s1stat.st_size) {
+                               warnx("Insufficient reserved space before FAT "
+                                       "(%u bytes available)" USE_F, u);
+                               return 0;
+                       }
+                       /* Check we have enough space for the old bpb */
+                       if (disk_buf.b[1] > bootstrap.b[1]) {
+                               /* old BPB is larger, allow if extra zeros */
+                               if (!is_zero(disk_buf.b + 2 + bootstrap.b[1],
+                                   disk_buf.b[1] - bootstrap.b[1])) {
+                                       warnx("Old BPB too big" USE_F);
+                                           return 0;
+                               }
+                               u = bootstrap.b[1];
+                       } else {
+                               /* Old BPB is shorter, leave zero filled */
+                               u = disk_buf.b[1];
+                       }
+                       memcpy(bootstrap.b + 2, disk_buf.b + 2, u);
+               }
+               #undef USE_F
+       }
+
+       /*
+        * Fill in any user-specified options into the
+        *      struct x86_boot_params
+        * that follows the magic number.
+        * See sys/arch/i386/stand/bootxx/bootxx.S for more information.
+        */
+       if (update_i386_boot_params(params, (void *)(magic + 1)))
+               return 0;
+
+       if (params->flags & IB_NOWRITE) {
+               return 1;
+       }
+
+       /* Copy new bootstrap data into disk buffer, ignoring label area */
+       memcpy(&disk_buf, &bootstrap, 512);
+       if (params->s1stat.st_size > 512 * 2) {
+               memcpy(disk_buf.b + 2 * 512, bootstrap.b + 2 * 512,
+                   params->s1stat.st_size - 2 * 512);
+               /* Zero pad to 512 byte sector boundary */
+               memset(disk_buf.b + params->s1stat.st_size, 0,
+                       (8192 - params->s1stat.st_size) & 511);
+       }
+
+       return write_boot_area(params, disk_buf.b, sizeof disk_buf.b);
+}
+
+static int
+i386_editboot(ib_params *params)
+{
+       int             retval;
+       uint8_t         buf[512];
+       ssize_t         rv;
+       uint32_t        magic;
+       uint32_t        offset;
+       struct x86_boot_params  *bpp;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+
+       retval = 0;
+
+       /*
+        * Read in the existing bootstrap.
+        * Look in any of the first 4 sectors.
+        */
+
+       bpp = NULL;
+       for (offset = 0; offset < 4 * 512; offset += 512) {
+               rv = pread(params->fsfd, &buf, sizeof buf, offset);
+               if (rv == -1) {
+                       warn("Reading `%s'", params->filesystem);
+                       goto done;
+               } else if (rv != sizeof buf) {
+                       warnx("Reading `%s': short read", params->filesystem);
+                       goto done;
+               }
+
+               /* Magic number is 4 bytes in (to allow for a jmps) */
+               /* Also allow any of the magic numbers. */
+               magic = le32toh(*(uint32_t *)(buf + 4)) | 0xf;
+               if (magic != (X86_BOOT_MAGIC_1 | 0xf))
+                       continue;
+
+               /* The parameters are just after the magic number */
+               bpp = (void *)(buf + 8);
+               break;
+       }
+       if (bpp == NULL) {
+               warnx("Invalid magic in existing bootstrap");
+               goto done;
+       }
+
+       /*
+        * Fill in any user-specified options into the
+        *      struct x86_boot_params
+        * that's 8 bytes in from the start of the third sector.
+        * See sys/arch/i386/stand/bootxx/bootxx.S for more information.
+        */
+       if (update_i386_boot_params(params, bpp))
+               goto done;
+
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+
+       /*
+        * Write boot code back
+        */
+       rv = pwrite(params->fsfd, buf, sizeof buf, offset);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if (rv != sizeof buf) {
+               warnx("Writing `%s': short write, %zd bytes (should be %zu)",
+                   params->filesystem, rv, sizeof(buf));
+               goto done;
+       }
+
+       retval = 1;
+
+ done:
+       return retval;
+}
diff --git a/usr.sbin/installboot/arch/landisk.c b/usr.sbin/installboot/arch/landisk.c
new file mode 100644 (file)
index 0000000..a5d4ef2
--- /dev/null
@@ -0,0 +1,250 @@
+/*     $NetBSD: landisk.c,v 1.5 2009/05/07 07:03:39 lukem Exp $        */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by David Laight.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: landisk.c,v 1.5 2009/05/07 07:03:39 lukem Exp $");
+#endif /* !__lint */
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <err.h>
+#include <md5.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "installboot.h"
+
+static int landisk_setboot(ib_params *);
+
+struct ib_mach ib_mach_landisk =
+       { "landisk", landisk_setboot, no_clearboot, no_editboot,
+         IB_TIMEOUT };
+
+static int
+landisk_setboot(ib_params *params)
+{
+       struct mbr_sector mbr;
+       struct landisk_boot_params bp, *bpp;
+       uint8_t *bootstrapbuf;
+       ssize_t rv;
+       uint32_t magic;
+       size_t bootstrapsize;
+       int retval, i;
+       uint32_t bplen;
+       int bpbsize;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(params->s1fd != -1);
+       assert(params->stage1 != NULL);
+
+       retval = 0;
+       bootstrapbuf = NULL;
+
+       /*
+        * There is only 8k of space in a FFSv1 partition (and ustarfs)
+        * so ensure we don't splat over anything important.
+        */
+       if (params->s1stat.st_size > 8192) {
+               warnx("stage1 bootstrap `%s' is larger than 8192 bytes",
+                       params->stage1);
+               goto done;
+       }
+
+       /*
+        * Read in the existing MBR.
+        */
+       rv = pread(params->fsfd, &mbr, sizeof(mbr), MBR_BBSECTOR);
+       if (rv == -1) {
+               warn("Reading `%s'", params->filesystem);
+               goto done;
+       } else if (rv != sizeof(mbr)) {
+               warnx("Reading `%s': short read", params->filesystem);
+               goto done;
+       }
+       if (mbr.mbr_magic != le16toh(MBR_MAGIC)) {
+               if (params->flags & IB_VERBOSE) {
+                       printf(
+                   "Ignoring MBR with invalid magic in sector 0 of `%s'\n",
+                           params->filesystem);
+               }
+               memset(&mbr, 0, sizeof(mbr));
+       }
+
+       /*
+        * Allocate a buffer, with space to round up the input file
+        * to the next block size boundary, and with space for the boot
+        * block.
+        */
+       bootstrapsize = roundup(params->s1stat.st_size, 512);
+
+       bootstrapbuf = malloc(bootstrapsize);
+       if (bootstrapbuf == NULL) {
+               warn("Allocating %zu bytes",  bootstrapsize);
+               goto done;
+       }
+       memset(bootstrapbuf, 0, bootstrapsize);
+
+       /*
+        * Read the file into the buffer.
+        */
+       rv = pread(params->s1fd, bootstrapbuf, params->s1stat.st_size, 0);
+       if (rv == -1) {
+               warn("Reading `%s'", params->stage1);
+               goto done;
+       } else if (rv != params->s1stat.st_size) {
+               warnx("Reading `%s': short read", params->stage1);
+               goto done;
+       }
+
+       magic = *(uint32_t *)(bootstrapbuf + 512 * 2 + 4);
+       if (magic != htole32(LANDISK_BOOT_MAGIC_1)) {
+               warnx("Invalid magic in stage1 boostrap %x != %x",
+                       magic, htole32(LANDISK_BOOT_MAGIC_1));
+               goto done;
+       }
+
+       /*
+        * Determine size of BIOS Parameter Block (BPB) to copy from
+        * original MBR to the temporary buffer by examining the first
+        * few instruction in the new bootblock.  Supported values:
+        *      2b a0 11        jmp ENDOF(mbr_bpbFAT32)+1, nop
+        *      (anything else) ; don't preserve
+        */
+       bpbsize = 0;
+#if 0
+       if (bootstrapbuf[1] == 0xa0 && bootstrapbuf[2] == 0x11 &&
+           (bootstrapbuf[0] == 0x2b /*|| bootstrapbuf[0] == 0x1d*/)) {
+               bpbsize = bootstrapbuf[0] + 2 - MBR_BPB_OFFSET;
+       }
+#endif
+
+       /*
+        * Ensure bootxx hasn't got any code or data (i.e, non-zero bytes) in
+        * the partition table.
+        */
+       for (i = 0; i < (int)sizeof(mbr.mbr_parts); i++) {
+               if (*(uint8_t *)(bootstrapbuf + MBR_PART_OFFSET + i) != 0) {
+                       warnx(
+                   "Partition table has non-zero byte at offset %d in `%s'",
+                           MBR_PART_OFFSET + i, params->stage1);
+                       goto done;
+               }
+       }
+
+#if 0
+       /*
+        * Copy the BPB and the partition table from the original MBR to the
+        * temporary buffer so that they're written back to the fs.
+        */
+       if (bpbsize != 0) {
+               if (params->flags & IB_VERBOSE)
+                       printf("Preserving %d (%#x) bytes of the BPB\n",
+                           bpbsize, bpbsize);
+               (void)memcpy(bootstrapbuf + MBR_BPB_OFFSET, &mbr.mbr_bpb,
+                   bpbsize);
+       }
+#endif
+       memcpy(bootstrapbuf + MBR_PART_OFFSET, &mbr.mbr_parts,
+           sizeof(mbr.mbr_parts));
+
+       /*
+        * Fill in any user-specified options into the
+        *      struct landisk_boot_params
+        * that's 8 bytes in from the start of the third sector.
+        * See sys/arch/landisk/stand/bootxx/bootxx.S for more information.
+        */
+       bpp = (void *)(bootstrapbuf + 512 * 2 + 8);
+       bplen = le32toh(bpp->bp_length);
+       if (bplen > sizeof bp)
+               /* Ignore pad space in bootxx */
+               bplen = sizeof bp;
+       /* Take (and update) local copy so we handle size mismatches */
+       memset(&bp, 0, sizeof bp);
+       memcpy(&bp, bpp, bplen);
+       if (params->flags & IB_TIMEOUT)
+               bp.bp_timeout = htole32(params->timeout);
+       /* Check we aren't trying to set anything we can't save */
+       if (bplen < sizeof bp && memcmp((char *)&bp + bplen,
+                                       (char *)&bp + bplen + 1,
+                                       sizeof bp - bplen - 1) != 0) {
+               warnx("Patch area in stage1 bootstrap is too small");
+               goto done;
+       }
+       memcpy(bpp, &bp, bplen);
+
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+
+       /*
+        * Write MBR code to sector zero.
+        */
+       rv = pwrite(params->fsfd, bootstrapbuf, 512, 0);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if (rv != 512) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       }
+
+       /*
+        * Skip disklabel in sector 1 and write bootxx to sectors 2..N.
+        */
+       rv = pwrite(params->fsfd, bootstrapbuf + 512 * 2,
+                   bootstrapsize - 512 * 2, 512 * 2);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if ((size_t)rv != bootstrapsize - 512 * 2) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       }
+
+       retval = 1;
+
+ done:
+       if (bootstrapbuf)
+               free(bootstrapbuf);
+       return retval;
+}
diff --git a/usr.sbin/installboot/arch/macppc.c b/usr.sbin/installboot/arch/macppc.c
new file mode 100644 (file)
index 0000000..1f4e88b
--- /dev/null
@@ -0,0 +1,186 @@
+/*     $NetBSD: macppc.c,v 1.11 2008/05/24 19:15:21 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: macppc.c,v 1.11 2008/05/24 19:15:21 tsutsui Exp $");
+#endif /* !__lint */
+
+#include <sys/param.h>
+#ifndef HAVE_NBTOOL_CONFIG_H
+#include <sys/ioctl.h>
+#include <sys/dkio.h>
+#include <errno.h>
+#endif
+
+#include <assert.h>
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "installboot.h"
+
+static struct bbinfo_params bbparams = {
+       MACPPC_BBINFO_MAGIC,
+       MACPPC_BOOT_BLOCK_OFFSET,
+       MACPPC_BOOT_BLOCK_BLOCKSIZE,
+       MACPPC_BOOT_BLOCK_MAX_SIZE,
+       0,
+       BBINFO_BIG_ENDIAN,
+};
+
+static int writeapplepartmap(ib_params *, struct bbinfo_params *, uint8_t *);
+
+static int macppc_clearboot(ib_params *);
+static int macppc_setboot(ib_params *);
+
+struct ib_mach ib_mach_macppc =
+       { "macppc", macppc_setboot, macppc_clearboot, no_editboot,
+               IB_STAGE2START };
+
+static int
+macppc_clearboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+               /* XXX: maybe clear the apple partition map too? */
+       return (shared_bbinfo_clearboot(params, &bbparams, NULL));
+}
+
+static int
+macppc_setboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+       return (shared_bbinfo_setboot(params, &bbparams, writeapplepartmap));
+}
+
+
+static int
+writeapplepartmap(ib_params *params, struct bbinfo_params *bb_params,
+    uint8_t *bb)
+{
+       struct apple_drvr_map dm;
+       struct apple_part_map_entry pme;
+       int rv;
+
+       assert (params != NULL);
+       assert (bb_params != NULL);
+       assert (bb != NULL);
+
+       if (params->flags & IB_NOWRITE)
+               return (1);
+
+               /* block 0: driver map  */
+       if (pread(params->fsfd, &dm, MACPPC_BOOT_BLOCK_BLOCKSIZE, 0) !=
+           MACPPC_BOOT_BLOCK_BLOCKSIZE) {
+               warn("Can't read sector 0 of `%s'", params->filesystem);
+               return (0);
+       }
+       dm.sbSig =              htobe16(APPLE_DRVR_MAP_MAGIC);
+       dm.sbBlockSize =        htobe16(512);
+       dm.sbBlkCount =         htobe32(0);
+
+       rv = pwrite(params->fsfd, &dm, MACPPC_BOOT_BLOCK_BLOCKSIZE, 0);
+#ifdef DIOCWLABEL
+       if (rv == -1 && errno == EROFS) {
+               /*
+                * block 0 is LABELSECTOR which might be protected by
+                * bounds_check_with_label(9).
+                */
+               int enable;
+
+               enable = 1;
+               rv = ioctl(params->fsfd, DIOCWLABEL, &enable);
+               if (rv != 0) {
+                       warn("Cannot enable writes to the label sector");
+                       return 0;
+               }
+
+               rv = pwrite(params->fsfd, &dm, MACPPC_BOOT_BLOCK_BLOCKSIZE, 0);
+
+               /* Reset write-protect. */
+               enable = 0;
+               (void)ioctl(params->fsfd, DIOCWLABEL, &enable);
+       }
+#endif
+       if (rv != MACPPC_BOOT_BLOCK_BLOCKSIZE) {
+               warn("Can't write sector 0 of `%s'", params->filesystem);
+               return (0);
+       }
+
+               /* block 1: Apple Partition Map */
+       memset(&pme, 0, sizeof(pme));
+       pme.pmSig =             htobe16(APPLE_PART_MAP_ENTRY_MAGIC);
+       pme.pmMapBlkCnt =       htobe32(2);
+       pme.pmPyPartStart =     htobe32(1);
+       pme.pmPartBlkCnt =      htobe32(2);
+       pme.pmDataCnt =         htobe32(2);
+       strlcpy(pme.pmPartName, "Apple", sizeof(pme.pmPartName));
+       strlcpy(pme.pmPartType, "Apple_partition_map", sizeof(pme.pmPartType));
+       pme.pmPartStatus =      htobe32(0x37);
+       if (pwrite(params->fsfd, &pme, MACPPC_BOOT_BLOCK_BLOCKSIZE,
+           1 * MACPPC_BOOT_BLOCK_BLOCKSIZE) != MACPPC_BOOT_BLOCK_BLOCKSIZE) {
+               warn("Can't write Apple Partition Map into sector 1 of `%s'",
+                   params->filesystem);
+               return (0);
+       }
+
+               /* block 2: NetBSD partition */
+       memset(&pme, 0, sizeof(pme));
+       pme.pmSig =             htobe16(APPLE_PART_MAP_ENTRY_MAGIC);
+       pme.pmMapBlkCnt =       htobe32(2);
+       pme.pmPyPartStart =     htobe32(4);
+       pme.pmPartBlkCnt =      htobe32(0x7fffffff);
+       pme.pmDataCnt =         htobe32(0x7fffffff);
+       strlcpy(pme.pmPartName, "NetBSD", sizeof(pme.pmPartName));
+       strlcpy(pme.pmPartType, "NetBSD/macppc", sizeof(pme.pmPartType));
+       pme.pmPartStatus =      htobe32(0x3b);
+       pme.pmBootSize =        htobe32(roundup(params->s1stat.st_size, 512));
+       pme.pmBootLoad =        htobe32(0x4000);
+       pme.pmBootEntry =       htobe32(0x4000);
+       strlcpy(pme.pmProcessor, "PowerPC", sizeof(pme.pmProcessor));
+       if (pwrite(params->fsfd, &pme, MACPPC_BOOT_BLOCK_BLOCKSIZE,
+           2 * MACPPC_BOOT_BLOCK_BLOCKSIZE) != MACPPC_BOOT_BLOCK_BLOCKSIZE) {
+               warn("Can't write Apple Partition Map into sector 2 of `%s'",
+                   params->filesystem);
+               return (0);
+       }
+
+       return (1);
+}
diff --git a/usr.sbin/installboot/arch/news.c b/usr.sbin/installboot/arch/news.c
new file mode 100644 (file)
index 0000000..27acd8b
--- /dev/null
@@ -0,0 +1,166 @@
+/*     $NetBSD: news.c,v 1.7 2008/04/28 20:24:16 martin Exp $ */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn and Izumi Tsutsui.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: news.c,v 1.7 2008/04/28 20:24:16 martin Exp $");
+#endif /* !__lint */
+
+#include <sys/param.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"
+
+static int news_copydisklabel(ib_params *, struct bbinfo_params *, uint8_t *);
+
+static int news68k_clearboot(ib_params *);
+static int news68k_setboot(ib_params *);
+static int newsmips_clearboot(ib_params *);
+static int newsmips_setboot(ib_params *);
+
+struct ib_mach ib_mach_news68k =
+       { "news68k", news68k_setboot, news68k_clearboot, no_editboot,
+               IB_STAGE2START };
+
+struct ib_mach ib_mach_newsmips =
+       { "newsmips", newsmips_setboot, newsmips_clearboot, no_editboot,
+               IB_STAGE2START };
+
+/*
+ * news68k specific support
+ */
+
+static struct bbinfo_params news68k_bbparams = {
+       NEWS68K_BBINFO_MAGIC,
+       NEWS_BOOT_BLOCK_OFFSET,         /* write all 8K (including disklabel) */
+       NEWS_BOOT_BLOCK_BLOCKSIZE,
+       NEWS_BOOT_BLOCK_MAX_SIZE,
+       0,
+       BBINFO_BIG_ENDIAN,
+};
+
+static int
+news68k_clearboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+       return (shared_bbinfo_clearboot(params, &news68k_bbparams,
+           news_copydisklabel));
+}
+
+static int
+news68k_setboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+       return (shared_bbinfo_setboot(params, &news68k_bbparams,
+           news_copydisklabel));
+}
+
+
+/*
+ * newsmips specific support
+ */
+
+static struct bbinfo_params newsmips_bbparams = {
+       NEWSMIPS_BBINFO_MAGIC,
+       NEWS_BOOT_BLOCK_OFFSET,         /* write all 8K (including disklabel) */
+       NEWS_BOOT_BLOCK_BLOCKSIZE,
+       NEWS_BOOT_BLOCK_MAX_SIZE,
+       0,
+       BBINFO_BIG_ENDIAN,
+};
+
+static int
+newsmips_clearboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+       return (shared_bbinfo_clearboot(params, &newsmips_bbparams,
+           news_copydisklabel));
+}
+
+static int
+newsmips_setboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+       return (shared_bbinfo_setboot(params, &newsmips_bbparams,
+           news_copydisklabel));
+}
+
+
+/*
+ * news_copydisklabel --
+ *     copy disklabel from existing location on disk into bootstrap,
+ *     as the primary bootstrap contains the disklabel.
+ */
+static int
+news_copydisklabel(ib_params *params, struct bbinfo_params *bbparams,
+       uint8_t *bb)
+{
+       uint8_t boot00[NEWS_BOOT_BLOCK_BLOCKSIZE];
+       ssize_t rv;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(bbparams != NULL);
+       assert(bb != NULL);
+
+               /* Read label sector to copy disklabel from */
+       memset(boot00, 0, sizeof(boot00));
+       rv = pread(params->fsfd, boot00, sizeof(boot00), 0);
+       if (rv == -1) {
+               warn("Reading label sector from `%s'", params->filesystem);
+               return (0);
+       }
+               /* Copy disklabel */
+       memcpy(bb + NEWS_BOOT_BLOCK_LABELOFFSET,
+           boot00 + NEWS_BOOT_BLOCK_LABELOFFSET,
+           sizeof(boot00) - NEWS_BOOT_BLOCK_LABELOFFSET);
+
+       return (1);
+}
diff --git a/usr.sbin/installboot/arch/next68k.c b/usr.sbin/installboot/arch/next68k.c
new file mode 100644 (file)
index 0000000..438dd13
--- /dev/null
@@ -0,0 +1,267 @@
+/* $NetBSD: next68k.c,v 1.7 2010/01/07 13:26:00 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by David Laight and Christian Limpach.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: next68k.c,v 1.7 2010/01/07 13:26:00 tsutsui Exp $");
+#endif /* !__lint */
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <err.h>
+#include <md5.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "installboot.h"
+
+static uint16_t nextstep_checksum(const void *, const void *);
+static int next68k_setboot(ib_params *);
+
+struct ib_mach ib_mach_next68k =
+       { "next68k", next68k_setboot, no_clearboot, no_editboot, 0};
+
+static uint16_t
+nextstep_checksum(const void *vbuf, const void *vlimit)
+{
+       const uint16_t *buf = vbuf;
+       const uint16_t *limit = vlimit;
+       u_int sum = 0;
+
+       while (buf < limit) {
+               sum += be16toh(*buf++);
+       }
+       sum += (sum >> 16);
+       return (sum & 0xffff);
+}
+
+static int
+next68k_setboot(ib_params *params)
+{
+       int retval, labelupdated;
+       uint8_t *bootbuf;
+       size_t bootsize;
+       ssize_t rv;
+       uint32_t cd_secsize;
+       int sec_netonb_mult;
+       struct next68k_disklabel *next68klabel;
+       uint16_t *checksum;
+       uint32_t fp, b0, b1;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(params->s1fd != -1);
+       assert(params->stage1 != NULL);
+
+       retval = 0;
+       labelupdated = 0;
+       bootbuf = NULL;
+
+       next68klabel = malloc(NEXT68K_LABEL_SIZE);
+       if (next68klabel == NULL) {
+               warn("Allocating %lu bytes", (unsigned long)NEXT68K_LABEL_SIZE);
+               goto done;
+       }
+
+       /*
+        * Read in the next68k disklabel
+        */
+       rv = pread(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE,
+           NEXT68K_LABEL_SECTOR * params->sectorsize + NEXT68K_LABEL_OFFSET);
+       if (rv == -1) {
+               warn("Reading `%s'", params->filesystem);
+               goto done;
+       }
+       if (rv != NEXT68K_LABEL_SIZE) {
+               warnx("Reading `%s': short read", params->filesystem);
+               goto done;
+       }
+       if (be32toh(next68klabel->cd_version) == NEXT68K_LABEL_CD_V3) {
+               checksum = &next68klabel->NEXT68K_LABEL_cd_v3_checksum;
+       } else {
+               checksum = &next68klabel->cd_checksum;
+       }
+       if (nextstep_checksum (next68klabel, checksum) !=
+           be16toh(*checksum)) {
+               warn("Disklabel checksum invalid on `%s'",
+                   params->filesystem);
+               goto done;
+       }
+
+       cd_secsize = be32toh(next68klabel->cd_secsize);
+       sec_netonb_mult = (cd_secsize / params->sectorsize);
+
+       /*
+        * Allocate a buffer, with space to round up the input file
+        * to the next block size boundary, and with space for the boot
+        * block.
+        */
+       bootsize = roundup(params->s1stat.st_size, cd_secsize);
+
+       bootbuf = malloc(bootsize);
+       if (bootbuf == NULL) {
+               warn("Allocating %zu bytes", bootsize);
+               goto done;
+       }
+       memset(bootbuf, 0, bootsize);
+
+       /*
+        * Read the file into the buffer.
+        */
+       rv = pread(params->s1fd, bootbuf, params->s1stat.st_size, 0);
+       if (rv == -1) {
+               warn("Reading `%s'", params->stage1);
+               goto done;
+       } else if (rv != params->s1stat.st_size) {
+               warnx("Reading `%s': short read", params->stage1);
+               goto done;
+       }
+
+       if (bootsize > be16toh(next68klabel->cd_front) * cd_secsize - 
+           NEXT68K_LABEL_SIZE) {
+               warnx("Boot program is larger than front porch space");
+               goto done;
+       }
+
+       fp = be16toh(next68klabel->cd_front);
+       b0 = be32toh(next68klabel->cd_boot_blkno[0]);
+       b1 = be32toh(next68klabel->cd_boot_blkno[1]);
+
+       if (b0 > fp)
+               b0 = fp;
+       if (b1 > fp)
+               b1 = fp;
+       if (((bootsize / cd_secsize) > b1 - b0) ||
+           ((bootsize / cd_secsize) > fp - b1)) {
+               if (2 * bootsize > (fp * cd_secsize - NEXT68K_LABEL_SIZE))
+                       /* can only fit one copy */
+                       b0 = b1 = NEXT68K_LABEL_SIZE / cd_secsize;
+               else {
+                       if (2 * bootsize > (fp * cd_secsize - 
+                               NEXT68K_LABEL_DEFAULTBOOT0_1 *
+                               params->sectorsize))
+                               /* can fit two copies starting after label */
+                               b0 = NEXT68K_LABEL_SIZE / cd_secsize;
+                       else
+                               /* can fit two copies starting at default 1 */
+                               b0 = NEXT68K_LABEL_DEFAULTBOOT0_1 /
+                                       sec_netonb_mult;
+                       /* try to fit 2nd copy at default 2 */
+                       b1 = NEXT68K_LABEL_DEFAULTBOOT0_2 / sec_netonb_mult;
+                       if (fp < b1)
+                               b1 = fp;
+                       if (bootsize / cd_secsize > (fp - b1))
+                               /* fit 2nd copy before front porch */
+                               b1 = fp - bootsize / cd_secsize;
+               }
+       }
+       if (next68klabel->cd_boot_blkno[0] != (int32_t)htobe32(b0)) {
+               next68klabel->cd_boot_blkno[0] = htobe32(b0);
+               labelupdated = 1;
+       }
+       if (next68klabel->cd_boot_blkno[1] != (int32_t)htobe32(b1)) {
+               next68klabel->cd_boot_blkno[1] = htobe32(b1);
+               labelupdated = 1;
+       }
+       if (params->flags & IB_VERBOSE)
+               printf("Boot programm locations%s: %d %d\n",
+                   labelupdated ? " updated" : "", b0 * sec_netonb_mult,
+                   b1 * sec_netonb_mult);
+
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+
+       /*
+        * Write the updated next68k disklabel
+        */
+       if (labelupdated) {
+               if (params->flags & IB_VERBOSE)
+                       printf ("Writing updated label\n");
+               *checksum = htobe16(nextstep_checksum (next68klabel,
+                                       checksum));
+               rv = pwrite(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE,
+                   NEXT68K_LABEL_SECTOR * params->sectorsize +
+                   NEXT68K_LABEL_OFFSET);
+               if (rv == -1) {
+                       warn("Writing `%s'", params->filesystem);
+                       goto done;
+               }
+               if (rv != NEXT68K_LABEL_SIZE) {
+                       warnx("Writing `%s': short write", params->filesystem);
+                       goto done;
+               }
+       }
+       
+       b0 *= sec_netonb_mult;
+       b1 *= sec_netonb_mult;
+
+       /*
+        * Write boot program to locations b0 and b1 (if different).
+        */
+       for (;;) {
+               if (params->flags & IB_VERBOSE)
+                       printf ("Writing boot program at %d\n", b0);
+               rv = pwrite(params->fsfd, bootbuf, bootsize,
+                   b0 * params->sectorsize);
+               if (rv == -1) {
+                       warn("Writing `%s' at %d", params->filesystem, b0);
+                       goto done;
+               }
+               if ((size_t)rv != bootsize) {
+                       warnx("Writing `%s' at %d: short write", 
+                           params->filesystem, b0);
+                       goto done;
+               }
+               if (b0 == b1)
+                       break;
+               b0 = b1;
+       }
+
+       retval = 1;
+
+ done:
+       if (bootbuf)
+               free(bootbuf);
+       if (next68klabel)
+               free(next68klabel);
+       return retval;
+}
diff --git a/usr.sbin/installboot/arch/pmax.c b/usr.sbin/installboot/arch/pmax.c
new file mode 100644 (file)
index 0000000..bdbdde7
--- /dev/null
@@ -0,0 +1,369 @@
+/*     $NetBSD: pmax.c,v 1.14 2009/04/05 11:55:39 lukem Exp $  */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Simon Burge.
+ *
+ * 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.
+ *
+ * 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) 1999 Ross Harvey.  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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Ross Harvey
+ *     for the NetBSD Project.
+ * 4. 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) 1999 Christopher G. Demetriou.  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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Christopher G. Demetriou
+ *     for the NetBSD Project.
+ * 4. 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(__lint)
+__RCSID("$NetBSD: pmax.c,v 1.14 2009/04/05 11:55:39 lukem Exp $");
+#endif /* !__lint */
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/exec_elf.h>
+
+#include "installboot.h"
+
+static int     load_bootstrap(ib_params *, char **,
+                               uint32_t *, uint32_t *, size_t *);
+
+static int pmax_clearboot(ib_params *);
+static int pmax_setboot(ib_params *);
+
+struct ib_mach ib_mach_pmax =
+       { "pmax", pmax_setboot, pmax_clearboot, no_editboot,
+               IB_STAGE1START | IB_APPEND | IB_SUNSUM };
+
+
+static int
+pmax_clearboot(ib_params *params)
+{
+       struct pmax_boot_block  bb;
+       ssize_t                 rv;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(sizeof(struct pmax_boot_block) == PMAX_BOOT_BLOCK_BLOCKSIZE);
+
+       rv = pread(params->fsfd, &bb, sizeof(bb), PMAX_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);
+       }
+
+       if (le32toh(bb.magic) != PMAX_BOOT_MAGIC) {
+               warnx(
+                   "Old boot block magic number invalid; boot block invalid");
+               return (0);
+       }
+
+       bb.map[0].num_blocks = bb.map[0].start_block = bb.mode = 0;
+       bb.magic = htole32(PMAX_BOOT_MAGIC);
+
+       if (params->flags & IB_SUNSUM) {
+               uint16_t        sum;
+
+               sum = compute_sunsum((uint16_t *)&bb);
+               if (! set_sunsum(params, (uint16_t *)&bb, sum))
+                       return (0);
+       }
+
+       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), PMAX_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);
+}
+
+static int
+pmax_setboot(ib_params *params)
+{
+       struct pmax_boot_block  bb;
+       uint32_t                startblock;
+       int                     retval;
+       char                    *bootstrapbuf;
+       size_t                  bootstrapsize;
+       uint32_t                bootstrapload, bootstrapexec;
+       ssize_t                 rv;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(params->s1fd != -1);
+       assert(params->stage1 != NULL);
+       assert(sizeof(struct pmax_boot_block) == PMAX_BOOT_BLOCK_BLOCKSIZE);
+
+       retval = 0;
+       bootstrapbuf = NULL;
+
+       if (! load_bootstrap(params, &bootstrapbuf, &bootstrapload,
+           &bootstrapexec, &bootstrapsize))
+               goto done;
+
+       rv = pread(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET);
+       if (rv == -1) {
+               warn("Reading `%s'", params->filesystem);
+               goto done;
+       } else if (rv != sizeof(bb)) {
+               warnx("Reading `%s': short read", params->filesystem);
+               goto done;
+       }
+
+               /* fill in the updated boot block fields */
+       if (params->flags & IB_APPEND) {
+               if (! S_ISREG(params->fsstat.st_mode)) {
+                       warnx(
+                   "`%s' must be a regular file to append a bootstrap",
+                           params->filesystem);
+                       goto done;
+               }
+               startblock = howmany(params->fsstat.st_size,
+                   PMAX_BOOT_BLOCK_BLOCKSIZE);
+       } else if (params->flags & IB_STAGE1START) {
+               startblock = params->s1start;
+       } else {
+               startblock = PMAX_BOOT_BLOCK_OFFSET / PMAX_BOOT_BLOCK_BLOCKSIZE
+                   + 1;
+       }
+
+       bb.map[0].start_block = htole32(startblock);
+       bb.map[0].num_blocks =
+           htole32(howmany(bootstrapsize, PMAX_BOOT_BLOCK_BLOCKSIZE));
+       bb.magic = htole32(PMAX_BOOT_MAGIC);
+       bb.load_addr = htole32(bootstrapload);
+       bb.exec_addr = htole32(bootstrapexec);
+       bb.mode = htole32(PMAX_BOOTMODE_CONTIGUOUS);
+
+       if (params->flags & IB_SUNSUM) {
+               uint16_t        sum;
+
+               sum = compute_sunsum((uint16_t *)&bb);
+               if (! set_sunsum(params, (uint16_t *)&bb, sum))
+                       goto done;
+       }
+
+       if (params->flags & IB_VERBOSE) {
+               printf("Bootstrap start sector: %u\n",
+                   le32toh(bb.map[0].start_block));
+               printf("Bootstrap sector count: %u\n",
+                   le32toh(bb.map[0].num_blocks));
+               printf("Bootstrap load address: %#x\n",
+                   le32toh(bb.load_addr));
+               printf("Bootstrap exec address: %#x\n",
+                   le32toh(bb.exec_addr));
+               printf("%sriting bootstrap\n",
+                   (params->flags & IB_NOWRITE) ? "Not w" : "W");
+       }
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+       rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize,
+            startblock * PMAX_BOOT_BLOCK_BLOCKSIZE);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if ((size_t)rv != bootstrapsize) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       }
+
+       if (params->flags & IB_VERBOSE)
+               printf("Writing boot block\n");
+       rv = pwrite(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if (rv != sizeof(bb)) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       } else {
+               retval = 1;
+       }
+
+ done:
+       if (bootstrapbuf)
+               free(bootstrapbuf);
+       return (retval);
+}
+
+
+#define MAX_SEGMENTS   10      /* We can load up to 10 segments */
+
+struct seglist {
+       Elf32_Addr      addr;
+       Elf32_Off       f_offset;
+       Elf32_Word      f_size;
+};
+
+static int
+load_bootstrap(ib_params *params, char **data,
+       uint32_t *loadaddr, uint32_t *execaddr, size_t *len)
+{
+       int             i, nsegs;
+       Elf32_Addr      lowaddr, highaddr;
+       Elf32_Ehdr      ehdr;
+       Elf32_Phdr      phdr;
+       struct seglist  seglist[MAX_SEGMENTS];
+
+       if ((pread(params->s1fd, &ehdr, sizeof(ehdr), 0)) != sizeof(ehdr)) {
+               warn("Reading `%s'", params->stage1);
+               return (0);
+       }
+       if ((memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) ||
+           (ehdr.e_ident[EI_CLASS] != ELFCLASS32)) {
+               warnx("No ELF header in `%s'", params->stage1);
+               return (0);
+       }
+
+       nsegs = highaddr = 0;
+       lowaddr = (uint32_t) ULONG_MAX;
+
+       for (i = 0; i < le16toh(ehdr.e_phnum); i++) {
+               if (pread(params->s1fd, &phdr, sizeof(phdr),
+                   (off_t) le32toh(ehdr.e_phoff) + i * sizeof(phdr))
+                   != sizeof(phdr)) {
+                       warn("Reading `%s'", params->stage1);
+                       return (0);
+               }
+               if (le32toh(phdr.p_type) != PT_LOAD)
+                       continue;
+
+               seglist[nsegs].addr = le32toh(phdr.p_paddr);
+               seglist[nsegs].f_offset = le32toh(phdr.p_offset);
+               seglist[nsegs].f_size = le32toh(phdr.p_filesz);
+               nsegs++;
+
+               if (le32toh(phdr.p_paddr) < lowaddr)
+                       lowaddr = le32toh(phdr.p_paddr);
+               if (le32toh(phdr.p_paddr) + le32toh(phdr.p_filesz) > highaddr)
+                       highaddr = le32toh(phdr.p_paddr) +
+                           le32toh(phdr.p_filesz);
+       }
+
+       *loadaddr = lowaddr;
+       *execaddr = le32toh(ehdr.e_entry);
+       *len = roundup(highaddr - lowaddr, PMAX_BOOT_BLOCK_BLOCKSIZE);
+       if ((*data = malloc(*len)) == NULL) {
+               warn("Allocating %lu bytes", (unsigned long) *len);
+               return (0);
+       }
+
+       /* Now load the bootstrap into memory */
+       for (i = 0; i < nsegs; i++) {
+               if ((Elf32_Word)pread(params->s1fd,
+                   *data + seglist[i].addr - lowaddr,
+                   seglist[i].f_size, (off_t)seglist[i].f_offset)
+                   != seglist[i].f_size) {
+                       warn("Reading `%s'", params->stage1);
+                       return (0);
+               }
+       }
+       return (1);
+}
diff --git a/usr.sbin/installboot/arch/sparc.c b/usr.sbin/installboot/arch/sparc.c
new file mode 100644 (file)
index 0000000..2629442
--- /dev/null
@@ -0,0 +1,128 @@
+/*     $NetBSD: sparc.c,v 1.11 2008/04/28 20:24:16 martin Exp $ */
+
+/*-
+ * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Kranenburg and Luke Mewburn.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: sparc.c,v 1.11 2008/04/28 20:24:16 martin Exp $");
+#endif /* !__lint */
+
+#include <sys/param.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"
+
+static struct bbinfo_params bbparams = {
+       SPARC_BBINFO_MAGIC,
+       SPARC_BOOT_BLOCK_OFFSET,
+       SPARC_BOOT_BLOCK_BLOCKSIZE,
+       SPARC_BOOT_BLOCK_MAX_SIZE,
+       32,                     /* leave room for a.out header */
+       BBINFO_BIG_ENDIAN,
+};
+
+static int sparc_clearheader(ib_params *, struct bbinfo_params *, uint8_t *);
+static int sparc_setheader(ib_params *, struct bbinfo_params *, uint8_t *);
+
+static int sparc_clearboot(ib_params *);
+static int sparc_setboot(ib_params *);
+
+struct ib_mach ib_mach_sparc =
+       { "sparc", sparc_setboot, sparc_clearboot, no_editboot,
+               IB_STAGE2START };
+
+static int
+sparc_clearboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+       return (shared_bbinfo_clearboot(params, &bbparams, sparc_clearheader));
+}
+
+static int
+sparc_setboot(ib_params *params)
+{
+       assert(params != NULL);
+
+       return (shared_bbinfo_setboot(params, &bbparams, sparc_setheader));
+}
+
+
+static int
+sparc_clearheader(ib_params *params, struct bbinfo_params *bb_params,
+       uint8_t *bb)
+{
+
+       assert(params != NULL);
+       assert(bb_params != NULL);
+       assert(bb != NULL);
+
+       memset(bb, 0, bb_params->headeroffset);
+       return (1);
+}
+
+static int
+sparc_setheader(ib_params *params, struct bbinfo_params *bb_params, uint8_t *bb)
+{
+
+       assert(params != NULL);
+       assert(bb_params != NULL);
+       assert(bb != NULL);
+
+       /*
+        * sun4c/sun4m PROMs require an a.out(5) format header.
+        * Old-style sun4 PROMs do not expect a header at all.
+        * To deal with this, we construct a header that is also executable
+        * code containing a forward branch that gets us past the 32-byte
+        * header where the actual code begins. In assembly:
+        *      .word   MAGIC           ! a NOP
+        *      ba,a    start           !
+        *      .skip   24              ! pad
+        * start:
+        */
+#define SUN_MAGIC      0x01030107
+#define SUN4_BASTART   0x30800007      /* i.e.: ba,a `start' */
+       *((uint32_t *)bb) = htobe32(SUN_MAGIC);
+       *((uint32_t *)bb + 1) = htobe32(SUN4_BASTART);
+
+       return (1);
+}
diff --git a/usr.sbin/installboot/arch/sparc64.c b/usr.sbin/installboot/arch/sparc64.c
new file mode 100644 (file)
index 0000000..4fc8772
--- /dev/null
@@ -0,0 +1,185 @@
+/*     $NetBSD: sparc64.c,v 1.18 2010/01/14 16:27:49 tsutsui Exp $     */
+
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * 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(__lint)
+__RCSID("$NetBSD: sparc64.c,v 1.18 2010/01/14 16:27:49 tsutsui Exp $");
+#endif /* !__lint */
+
+#include <sys/param.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"
+
+static int sparc64_clearboot(ib_params *);
+static int sparc64_setboot(ib_params *);
+
+struct ib_mach ib_mach_sparc64 =
+       { "sparc64", sparc64_setboot, sparc64_clearboot, no_editboot, 0};
+
+static int
+sparc64_clearboot(ib_params *params)
+{
+       char    bb[SPARC64_BOOT_BLOCK_MAX_SIZE];
+       ssize_t rv;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+
+       if (params->flags & (IB_STAGE1START | IB_STAGE2START)) {
+               warnx("`-b bno' and `-B bno' are not supported for %s",
+                   params->machine->name);
+               return (0);
+       }
+
+       /* first check that it _could_ exist here */
+       rv = pread(params->fsfd, &bb, sizeof(bb), SPARC64_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), SPARC64_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);
+}
+
+static int
+sparc64_setboot(ib_params *params)
+{
+       char            bb[SPARC64_BOOT_BLOCK_MAX_SIZE];
+       int             retval;
+       ssize_t         rv;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(params->s1fd != -1);
+       assert(params->stage1 != NULL);
+
+       retval = 0;
+
+       if (params->flags & (IB_STAGE1START | IB_STAGE2START)) {
+               warnx("`-b bno' and `-B bno' are not supported for %s",
+                   params->machine->name);
+               goto done;
+       }
+
+       memset(&bb, 0, SPARC64_BOOT_BLOCK_MAX_SIZE);
+       rv = read(params->s1fd, &bb, sizeof(bb));
+       if (rv == -1) {
+               warn("Reading `%s'", params->stage1);
+               goto done;
+       }
+
+       if (params->flags & IB_VERBOSE) {
+               printf("Bootstrap start sector: %u\n",
+                   SPARC64_BOOT_BLOCK_OFFSET / SPARC64_BOOT_BLOCK_BLOCKSIZE);
+               printf("Bootstrap byte count:   %u\n", (unsigned)rv);
+               printf("%sriting bootstrap\n",
+                   (params->flags & IB_NOWRITE) ? "Not w" : "W");
+       }
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+
+       rv = pwrite(params->fsfd, &bb, SPARC64_BOOT_BLOCK_MAX_SIZE,
+           SPARC64_BOOT_BLOCK_OFFSET);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if (rv != SPARC64_BOOT_BLOCK_MAX_SIZE) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       } else
+               retval = 1;
+
+ done:
+       return (retval);
+}
diff --git a/usr.sbin/installboot/arch/sun68k.c b/usr.sbin/installboot/arch/sun68k.c
new file mode 100644 (file)
index 0000000..a4c900b
--- /dev/null
@@ -0,0 +1,85 @@
+/*     $NetBSD: sun68k.c,v 1.21 2008/04/28 20:24:16 martin Exp $ */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: sun68k.c,v 1.21 2008/04/28 20:24:16 martin Exp $");
+#endif /* !__lint */
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <err.h>
+#include <stdio.h>
+
+#include "installboot.h"
+
+static int sun68k_clearboot(ib_params *);
+static int sun68k_setboot(ib_params *);
+
+struct ib_mach ib_mach_sun2 =
+       { "sun2", sun68k_setboot, sun68k_clearboot, no_editboot,
+               IB_STAGE2START };
+
+struct ib_mach ib_mach_sun3 =
+       { "sun3", sun68k_setboot, sun68k_clearboot, no_editboot,
+               IB_STAGE2START };
+
+static struct bbinfo_params bbparams = {
+       SUN68K_BBINFO_MAGIC,
+       SUN68K_BOOT_BLOCK_OFFSET,
+       SUN68K_BOOT_BLOCK_BLOCKSIZE,
+       SUN68K_BOOT_BLOCK_MAX_SIZE,
+       0,
+       BBINFO_BIG_ENDIAN,
+};
+
+static int
+sun68k_clearboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+       return (shared_bbinfo_clearboot(params, &bbparams, NULL));
+}
+
+static int
+sun68k_setboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+       return (shared_bbinfo_setboot(params, &bbparams, NULL));
+}
diff --git a/usr.sbin/installboot/arch/vax.c b/usr.sbin/installboot/arch/vax.c
new file mode 100644 (file)
index 0000000..453fc9a
--- /dev/null
@@ -0,0 +1,316 @@
+/*     $NetBSD: vax.c,v 1.13 2009/04/05 11:55:39 lukem Exp $   */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Simon Burge.
+ *
+ * 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.
+ *
+ * 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) 1999 Christopher G. Demetriou.  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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Christopher G. Demetriou
+ *     for the NetBSD Project.
+ * 4. 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(__lint)
+__RCSID("$NetBSD: vax.c,v 1.13 2009/04/05 11:55:39 lukem Exp $");
+#endif /* !__lint */
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "installboot.h"
+
+static int     load_bootstrap(ib_params *, char **,
+                   uint32_t *, uint32_t *, size_t *);
+
+static int vax_clearboot(ib_params *);
+static int vax_setboot(ib_params *);
+
+struct ib_mach ib_mach_vax =
+       { "vax", vax_setboot, vax_clearboot, no_editboot,
+               IB_STAGE1START | IB_APPEND | IB_SUNSUM };
+
+static int
+vax_clearboot(ib_params *params)
+{
+       struct vax_boot_block   bb;
+       ssize_t                 rv;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(sizeof(struct vax_boot_block) == VAX_BOOT_BLOCK_BLOCKSIZE);
+
+       rv = pread(params->fsfd, &bb, sizeof(bb), VAX_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);
+       }
+
+       if (bb.bb_id_offset * 2 != offsetof(struct vax_boot_block, bb_magic1)
+           || bb.bb_magic1 != VAX_BOOT_MAGIC1) {
+               warnx(
+                   "Old boot block magic number invalid; boot block invalid");
+               return (0);
+       }
+
+       bb.bb_id_offset = 1;
+       bb.bb_mbone = 0;
+       bb.bb_lbn_hi = 0;
+       bb.bb_lbn_low = 0;
+
+       if (params->flags & IB_SUNSUM) {
+               uint16_t        sum;
+
+               sum = compute_sunsum((uint16_t *)&bb);
+               if (! set_sunsum(params, (uint16_t *)&bb, sum))
+                       return (0);
+       }
+
+       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), VAX_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);
+}
+
+static int
+vax_setboot(ib_params *params)
+{
+       struct stat             bootstrapsb;
+       struct vax_boot_block   bb;
+       uint32_t                startblock;
+       int                     retval;
+       char                    *bootstrapbuf;
+       size_t                  bootstrapsize;
+       uint32_t                bootstrapload, bootstrapexec;
+       ssize_t                 rv;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(params->s1fd != -1);
+       assert(params->stage1 != NULL);
+       assert(sizeof(struct vax_boot_block) == VAX_BOOT_BLOCK_BLOCKSIZE);
+
+       retval = 0;
+       bootstrapbuf = NULL;
+
+       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 (! load_bootstrap(params, &bootstrapbuf, &bootstrapload,
+           &bootstrapexec, &bootstrapsize))
+               goto done;
+
+       rv = pread(params->fsfd, &bb, sizeof(bb), VAX_BOOT_BLOCK_OFFSET);
+       if (rv == -1) {
+               warn("Reading `%s'", params->filesystem);
+               goto done;
+       } else if (rv != sizeof(bb)) {
+               warnx("Reading `%s': short read", params->filesystem);
+               goto done;
+       }
+
+               /* fill in the updated boot block fields */
+       if (params->flags & IB_APPEND) {
+               struct stat     filesyssb;
+
+               if (fstat(params->fsfd, &filesyssb) == -1) {
+                       warn("Examining `%s'", params->filesystem);
+                       goto done;
+               }
+               if (!S_ISREG(filesyssb.st_mode)) {
+                       warnx(
+                   "`%s' must be a regular file to append a bootstrap",
+                           params->filesystem);
+                       goto done;
+               }
+               startblock = howmany(filesyssb.st_size,
+                   VAX_BOOT_BLOCK_BLOCKSIZE);
+       } else if (params->flags & IB_STAGE1START) {
+               startblock = params->s1start;
+       } else {
+               startblock = VAX_BOOT_BLOCK_OFFSET / VAX_BOOT_BLOCK_BLOCKSIZE
+                   + 1;
+       }
+
+       bb.bb_id_offset = offsetof(struct vax_boot_block, bb_magic1) / 2;
+       bb.bb_mbone = 1;
+       bb.bb_lbn_hi = htole16((uint16_t) (startblock >> 16));
+       bb.bb_lbn_low = htole16((uint16_t) (startblock >>  0));
+       /*
+        * Now the identification block
+        */
+       bb.bb_magic1 = VAX_BOOT_MAGIC1;
+       bb.bb_mbz1 = 0;
+       bb.bb_sum1 = ~(bb.bb_magic1 + bb.bb_mbz1 + bb.bb_pad1);
+
+       bb.bb_mbz2 = 0;
+       bb.bb_volinfo = VAX_BOOT_VOLINFO_NONE;
+       bb.bb_pad2a = 0;
+       bb.bb_pad2b = 0;
+
+       bb.bb_size = htole32(bootstrapsize / VAX_BOOT_BLOCK_BLOCKSIZE);
+       bb.bb_load = htole32(VAX_BOOT_LOAD);
+       bb.bb_entry = htole32(VAX_BOOT_ENTRY);
+       bb.bb_sum3 = htole32(le32toh(bb.bb_size) + le32toh(bb.bb_load) \
+           + le32toh(bb.bb_entry));
+
+       if (params->flags & IB_SUNSUM) {
+               uint16_t        sum;
+
+               sum = compute_sunsum((uint16_t *)&bb);
+               if (! set_sunsum(params, (uint16_t *)&bb, sum))
+                       goto done;
+       }
+
+       if (params->flags & IB_VERBOSE) {
+               printf("Bootstrap start sector: %u\n", startblock);
+               printf("Bootstrap sector count: %u\n", le32toh(bb.bb_size));
+               printf("%sriting bootstrap\n",
+                   (params->flags & IB_NOWRITE) ? "Not w" : "W");
+       }
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+       rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize,
+            startblock * VAX_BOOT_BLOCK_BLOCKSIZE);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if ((size_t)rv != bootstrapsize) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       }
+
+       if (params->flags & IB_VERBOSE)
+               printf("Writing boot block\n");
+       rv = pwrite(params->fsfd, &bb, sizeof(bb), VAX_BOOT_BLOCK_OFFSET);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if (rv != sizeof(bb)) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       } else {
+               retval = 1;
+       }
+
+ done:
+       if (bootstrapbuf)
+               free(bootstrapbuf);
+       return (retval);
+}
+
+static int
+load_bootstrap(ib_params *params, char **data,
+       uint32_t *loadaddr, uint32_t *execaddr, size_t *len)
+{
+       ssize_t cc;
+       size_t  buflen;
+
+       buflen = 512 * (VAX_BOOT_SIZE + 1);
+       *data = malloc(buflen);
+       if (*data == NULL) {
+               warn("Allocating %lu bytes", (unsigned long) buflen);
+               return (0);
+       }
+
+       cc = pread(params->s1fd, *data, buflen, 0);
+       if (cc <= 0) {
+               warn("Reading `%s'", params->stage1);
+               return (0);
+       }
+       if (cc > 512 * VAX_BOOT_SIZE) {
+               warnx("`%s': too large", params->stage1);
+               return (0);
+       }
+
+       *len = roundup(cc, VAX_BOOT_BLOCK_BLOCKSIZE);
+       *loadaddr = VAX_BOOT_LOAD;
+       *execaddr = VAX_BOOT_ENTRY;
+       return (1);
+}
diff --git a/usr.sbin/installboot/arch/x68k.c b/usr.sbin/installboot/arch/x68k.c
new file mode 100644 (file)
index 0000000..ee78cf7
--- /dev/null
@@ -0,0 +1,181 @@
+/*     $NetBSD: x68k.c,v 1.4 2008/04/28 20:24:16 martin Exp $  */
+
+/*-
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: x68k.c,v 1.4 2008/04/28 20:24:16 martin Exp $");
+#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"
+
+#define X68K_LABELOFFSET               64
+#define X68K_LABELSIZE         404 /* reserve 16 partitions */
+
+static int x68k_clearheader(ib_params *, struct bbinfo_params *, uint8_t *);
+
+static int x68k_clearboot(ib_params *);
+static int x68k_setboot(ib_params *);
+
+struct ib_mach ib_mach_x68k =
+       { "x68k", x68k_setboot, x68k_clearboot, no_editboot,
+               IB_STAGE1START | IB_STAGE2START };
+
+static struct bbinfo_params bbparams = {
+       X68K_BBINFO_MAGIC,
+       X68K_BOOT_BLOCK_OFFSET,
+       X68K_BOOT_BLOCK_BLOCKSIZE,
+       X68K_BOOT_BLOCK_MAX_SIZE,
+       X68K_LABELOFFSET + X68K_LABELSIZE, /* XXX */
+       BBINFO_BIG_ENDIAN,
+};
+
+static int
+x68k_clearboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+       if (params->flags & IB_STAGE1START) {
+               warnx("`-b bno' is not supported for %s",
+                       params->machine->name);
+               return 0;
+       }
+       return shared_bbinfo_clearboot(params, &bbparams, x68k_clearheader);
+}
+
+static int
+x68k_clearheader(ib_params *params, struct bbinfo_params *bb_params,
+       uint8_t *bb)
+{
+
+       assert(params != NULL);
+       assert(bb_params != NULL);
+       assert(bb != NULL);
+
+       memset(bb, 0, X68K_LABELOFFSET);
+       return 1;
+}
+
+static int
+x68k_setboot(ib_params *params)
+{
+       struct stat     bootstrapsb;
+       char            bb[X68K_BOOT_BLOCK_MAX_SIZE];
+       char            label[X68K_LABELSIZE];
+       uint32_t        s1start;
+       int             retval;
+       ssize_t         rv;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(params->s1fd != -1);
+       assert(params->stage1 != NULL);
+
+       retval = 0;
+
+       if (params->flags & IB_STAGE1START)
+               s1start = params->s1start;
+       else
+               s1start = X68K_BOOT_BLOCK_OFFSET /
+                   X68K_BOOT_BLOCK_BLOCKSIZE;
+
+       /* read disklabel on the target disk */
+       rv = pread(params->fsfd, label, sizeof label,
+                  s1start * X68K_BOOT_BLOCK_BLOCKSIZE + X68K_LABELOFFSET);
+       if (rv == -1) {
+               warn("Reading `%s'", params->filesystem);
+               goto done;
+       } else if (rv != sizeof label) {
+               warnx("Reading `%s': short read", params->filesystem);
+               goto done;
+       }
+
+       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;
+       }
+
+       /* read boot loader */
+       memset(&bb, 0, sizeof bb);
+       rv = read(params->s1fd, &bb, sizeof bb);
+       if (rv == -1) {
+               warn("Reading `%s'", params->stage1);
+               goto done;
+       }
+       /* then, overwrite disklabel */
+       memcpy(&bb[X68K_LABELOFFSET], &label, sizeof label);
+
+       if (params->flags & IB_VERBOSE) {
+               printf("Bootstrap start sector: %#x\n", s1start);
+               printf("Bootstrap byte count:   %#x\n", (unsigned)rv);
+               printf("%sriting bootstrap\n",
+                   (params->flags & IB_NOWRITE) ? "Not w" : "W");
+       }
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+
+       /* write boot loader and disklabel into the target disk */
+       rv = pwrite(params->fsfd, &bb, X68K_BOOT_BLOCK_MAX_SIZE,
+           s1start * X68K_BOOT_BLOCK_BLOCKSIZE);
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if (rv != X68K_BOOT_BLOCK_MAX_SIZE) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       } else
+               retval = 1;
+
+ done:
+       return (retval);
+}
diff --git a/usr.sbin/installboot/bbinfo.c b/usr.sbin/installboot/bbinfo.c
new file mode 100644 (file)
index 0000000..a0bbf56
--- /dev/null
@@ -0,0 +1,330 @@
+/*     $NetBSD: bbinfo.c,v 1.14 2009/04/05 11:55:39 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Fredette, Paul Kranenburg, and Luke Mewburn.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: bbinfo.c,v 1.14 2009/04/05 11:55:39 lukem Exp $");
+#endif /* !__lint */
+
+#include <sys/param.h>
+#ifndef HAVE_NBTOOL_CONFIG_H
+#include <sys/ioctl.h>
+#include <sys/dkio.h>
+#include <errno.h>
+#endif
+
+#include <assert.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "installboot.h"
+
+int
+shared_bbinfo_clearboot(ib_params *params, struct bbinfo_params *bbparams,
+       int (*callback)(ib_params *, struct bbinfo_params *, uint8_t *))
+{
+       uint8_t *bb;
+       ssize_t rv;
+       int     retval;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(bbparams != NULL);
+       assert((strlen(bbparams->magic) + 1) == 32);
+
+       retval = 0;
+       if ((bb = malloc(bbparams->maxsize)) == NULL) {
+               warn("Allocating %lu bytes for bbinfo",
+                   (unsigned long) bbparams->maxsize);
+               goto done;
+       }
+
+               /* First check that it _could_ exist here */
+       rv = pread(params->fsfd, bb, bbparams->maxsize, bbparams->offset);
+       if (rv == -1) {
+               warn("Reading `%s'", params->filesystem);
+               goto done;
+       } else if ((uint32_t)rv != bbparams->maxsize) {
+               warnx("Reading `%s': short read", params->filesystem);
+               goto done;
+       }
+
+               /* Now clear out (past the header offset) */
+       memset(bb + bbparams->headeroffset, 0,
+           bbparams->maxsize - bbparams->headeroffset);
+       if (callback != NULL && ! (*callback)(params, bbparams, bb))
+               goto done;
+
+       if (params->flags & IB_VERBOSE)
+               printf("%slearing boot block\n",
+                   (params->flags & IB_NOWRITE) ? "Not c" : "C");
+       if (params->flags & IB_NOWRITE) {
+               retval = 1;
+               goto done;
+       }
+
+       rv = pwrite(params->fsfd, bb, bbparams->maxsize, bbparams->offset);
+#ifdef DIOCWLABEL
+       if (rv == -1 && errno == EROFS) {
+               /*
+                * The first sector might be protected by
+                * bounds_check_with_label(9)
+                */
+               int enable;
+
+               enable = 1;
+               rv = ioctl(params->fsfd, DIOCWLABEL, &enable);
+               if (rv != 0) {
+                       warn("Cannot enable writes to the label sector");
+                       goto done;
+               }
+
+               rv = pwrite(params->fsfd, bb, bbparams->maxsize,
+                   bbparams->offset);
+
+               /* Reset write-protect. */
+               enable = 0;
+               (void)ioctl(params->fsfd, DIOCWLABEL, &enable);
+       }
+#endif
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if ((uint32_t)rv != bbparams->maxsize) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       } else
+               retval = 1;
+
+ done:
+       if (bb != NULL)
+               free(bb);
+       return (retval);
+}
+
+int
+shared_bbinfo_setboot(ib_params *params, struct bbinfo_params *bbparams,
+       int (*callback)(ib_params *, struct bbinfo_params *, uint8_t *))
+{
+       uint8_t         *bb;
+       int             retval;
+       ssize_t         rv;
+       size_t          bbi;
+       struct shared_bbinfo    *bbinfop;       /* bbinfo in prototype image */
+       uint32_t        maxblk, nblk, blk_i;
+       ib_block        *blocks;
+
+       assert(params != NULL);
+       assert(params->fsfd != -1);
+       assert(params->filesystem != NULL);
+       assert(params->fstype != NULL);
+       assert(params->s1fd != -1);
+       assert(params->stage1 != NULL);
+       assert(bbparams != NULL);
+       assert((strlen(bbparams->magic) + 1) == 32);
+
+       bbinfop = NULL;         /* XXXGCC -Wuninitialized [sparc64] */
+       retval = 0;
+       blocks = NULL;
+       if ((bb = malloc(bbparams->maxsize)) == NULL) {
+               warn("Allocating %lu bytes for bbinfo",
+                   (unsigned long) bbparams->maxsize);
+               goto done;
+       }
+
+       if (params->stage2 == NULL) {
+               warnx("Name of secondary bootstrap not provided");
+               goto done;
+       }
+
+       if (params->s1stat.st_size >
+           bbparams->maxsize - bbparams->headeroffset) {
+               warnx("`%s' cannot be larger than %lu bytes",
+                   params->stage1, (unsigned long)(bbparams->maxsize -
+                       bbparams->headeroffset));
+               goto done;
+       }
+
+       memset(bb, 0, bbparams->maxsize);
+       rv = read(params->s1fd, bb + bbparams->headeroffset,
+           bbparams->maxsize - bbparams->headeroffset);
+       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 + bbparams->headeroffset + 1, "ELF", strlen("ELF"))
+           == 0) {
+               warnx("`%s' is an ELF executable; need raw binary",
+                   params->stage1);
+               goto done;
+       }
+
+#define HOSTTOTARGET32(x) ((bbparams->endian == BBINFO_LITTLE_ENDIAN) \
+                           ? (uint32_t)htole32((x)) : (uint32_t)htobe32((x)))
+#define TARGET32TOHOST(x) ((bbparams->endian == BBINFO_LITTLE_ENDIAN) \
+                           ? (uint32_t)le32toh((x)) : (uint32_t)be32toh((x)))
+
+               /* Look for the bbinfo structure. */
+       bbinfop = NULL;
+       for (bbi = 0; bbi < bbparams->maxsize; bbi += sizeof(uint32_t)) {
+               bbinfop = (void *) (bb + bbparams->headeroffset + bbi);
+               if (memcmp(bbinfop->bbi_magic, bbparams->magic,
+                           sizeof(bbinfop->bbi_magic)) == 0)
+                       break;
+       }
+       if (bbi >= bbparams->maxsize) {
+               warnx("%s bbinfo structure not found in `%s'",
+                   params->machine->name, params->stage1);
+               goto done;
+       }
+       maxblk = TARGET32TOHOST(bbinfop->bbi_block_count);
+       if (maxblk == 0 || maxblk > (bbparams->maxsize / sizeof(uint32_t))) {
+               warnx("%s bbinfo structure in `%s' has preposterous size `%u'",
+                   params->machine->name, params->stage1, maxblk);
+               goto done;
+       }
+
+               /* 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;
+       }
+
+       if (S_ISREG(params->fsstat.st_mode)) {
+               if (fsync(params->fsfd) == -1)
+                       warn("Synchronising file system `%s'",
+                           params->filesystem);
+       } else {
+               /* Ensure the secondary bootstrap is on disk. */
+               sync();
+       }
+
+               /* 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 = HOSTTOTARGET32(nblk);
+       bbinfop->bbi_block_size = HOSTTOTARGET32(blocks[0].blocksize);
+       for (blk_i = 0; blk_i < nblk; blk_i++) {
+               bbinfop->bbi_block_table[blk_i] =
+                   HOSTTOTARGET32(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);
+                       goto done;
+               }
+       }
+       if (callback != NULL && ! (*callback)(params, bbparams, bb))
+               goto done;
+
+       if (params->flags & IB_VERBOSE) {
+               printf("Bootstrap start sector: %u\n",
+                   bbparams->offset / bbparams->blocksize);
+               printf("Bootstrap byte count:   %u\n", (unsigned)rv);
+               printf("Bootstrap block table:  "
+                       "%u entries of %u bytes available, %u used:",
+                   maxblk, blocks[0].blocksize, nblk);
+               for (blk_i = 0; blk_i < nblk; blk_i++)
+                       printf(" %llu",
+                           (unsigned long long)blocks[blk_i].block);
+               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, bbparams->maxsize, bbparams->offset);
+#ifdef DIOCWLABEL
+       if (rv == -1 && errno == EROFS) {
+               /*
+                * The first sector might be protected by
+                * bounds_check_with_label(9)
+                */
+               int enable;
+
+               enable = 1;
+               rv = ioctl(params->fsfd, DIOCWLABEL, &enable);
+               if (rv != 0) {
+                       warn("Cannot enable writes to the label sector");
+                       goto done;
+               }
+
+               rv = pwrite(params->fsfd, bb, bbparams->maxsize,
+                   bbparams->offset);
+
+               /* Reset write-protect. */
+               enable = 0;
+               (void)ioctl(params->fsfd, DIOCWLABEL, &enable);
+       }
+#endif
+       if (rv == -1) {
+               warn("Writing `%s'", params->filesystem);
+               goto done;
+       } else if ((uint32_t)rv != bbparams->maxsize) {
+               warnx("Writing `%s': short write", params->filesystem);
+               goto done;
+       } else {
+               retval = 1;
+       }
+
+ done:
+       if (blocks != NULL)
+               free(blocks);
+       if (bb != NULL)
+               free(bb);
+       return (retval);
+}
diff --git a/usr.sbin/installboot/ext2fs.c b/usr.sbin/installboot/ext2fs.c
new file mode 100644 (file)
index 0000000..a1c37e3
--- /dev/null
@@ -0,0 +1,468 @@
+/*     $NetBSD: ext2fs.c,v 1.6 2010/01/14 16:27:49 tsutsui Exp $       */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * 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) 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: ext2fs.c,v 1.6 2010/01/14 16:27:49 tsutsui Exp $");
+#endif /* !__lint */
+
+#include <sys/param.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 "installboot.h"
+
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+
+static int     ext2fs_read_disk_block(ib_params *, uint64_t, int, uint8_t []);
+static int     ext2fs_read_sblock(ib_params *, struct m_ext2fs *fs);
+static int     ext2fs_read_gdblock(ib_params *, struct m_ext2fs *fs);
+static int     ext2fs_find_disk_blocks(ib_params *, ino_t,
+                   int (*)(ib_params *, void *, uint64_t, uint32_t), void *);
+static int     ext2fs_findstage2_ino(ib_params *, void *, uint64_t, uint32_t);
+static int     ext2fs_findstage2_blocks(ib_params *, void *, uint64_t,
+                   uint32_t);
+
+
+/* This reads a disk block from the file system. */
+/* XXX: should be shared with ffs.c? */
+static int
+ext2fs_read_disk_block(ib_params *params, uint64_t blkno, int size,
+    uint8_t blk[])
+{
+       int rv;
+
+       assert(params != NULL);
+       assert(params->filesystem != NULL);
+       assert(params->fsfd != -1);
+       assert(size > 0);
+       assert(blk != NULL);
+
+       rv = pread(params->fsfd, blk, size, blkno * params->sectorsize);
+       if (rv == -1) {
+               warn("Reading block %llu in `%s'", 
+                   (unsigned long long)blkno, params->filesystem);
+               return 0;
+       } else if (rv != size) {
+               warnx("Reading block %llu in `%s': short read",
+                   (unsigned long long)blkno, params->filesystem);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int
+ext2fs_read_sblock(ib_params *params, struct m_ext2fs *fs)
+{
+       uint8_t sbbuf[SBSIZE];
+
+       if (ext2fs_read_disk_block(params, SBOFF / params->sectorsize, SBSIZE,
+           sbbuf) == 0)
+
+       e2fs_sbload((void *)sbbuf, &fs->e2fs);
+
+       if (fs->e2fs.e2fs_magic != E2FS_MAGIC)
+               return 0;
+
+       if (fs->e2fs.e2fs_rev > E2FS_REV1 ||
+           (fs->e2fs.e2fs_rev == E2FS_REV1 &&
+            (fs->e2fs.e2fs_first_ino != EXT2_FIRSTINO ||
+             fs->e2fs.e2fs_inode_size != EXT2_DINODE_SIZE ||
+             (fs->e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP) != 0)))
+               return 0;
+
+       fs->e2fs_ncg =
+           howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
+           fs->e2fs.e2fs_bpg);
+       /* XXX assume hw bsize = 512 */
+       fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
+       fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize;
+       fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
+       fs->e2fs_qbmask = fs->e2fs_bsize - 1;
+       fs->e2fs_bmask = ~fs->e2fs_qbmask;
+       fs->e2fs_ngdb =
+           howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd));
+       fs->e2fs_ipb = fs->e2fs_bsize / EXT2_DINODE_SIZE;
+       fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb;
+
+       return 1;
+}
+
+static int
+ext2fs_read_gdblock(ib_params *params, struct m_ext2fs *fs)
+{
+       uint8_t gdbuf[MAXBSIZE];
+       uint32_t gdpb;
+       int i;
+
+       gdpb = fs->e2fs_bsize / sizeof(struct ext2_gd);
+
+       for (i = 0; i < fs->e2fs_ngdb; i++) {
+               if (ext2fs_read_disk_block(params, fsbtodb(fs,
+                   fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i),
+                   SBSIZE, gdbuf) == 0)
+                       return 0;
+
+               e2fs_cgload((struct ext2_gd *)gdbuf, &fs->e2fs_gd[gdpb * i],
+                   (i == (fs->e2fs_ngdb - 1)) ?
+                   (fs->e2fs_ncg - gdpb * i) * sizeof(struct ext2_gd):
+                   fs->e2fs_bsize);
+       }
+
+       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
+ext2fs_find_disk_blocks(ib_params *params, ino_t ino, 
+       int (*callback)(ib_params *, void *, uint64_t, uint32_t),
+       void *state)
+{
+       uint8_t sbbuf[sizeof(struct m_ext2fs)];
+       struct m_ext2fs *fs;
+       uint8_t inodebuf[MAXBSIZE];
+       struct ext2fs_dinode inode_store, *inode;
+       int level_i;
+       int32_t blk, lblk, nblk;
+       int rv;
+#define LEVELS 4
+       struct {
+               uint32_t *blknums;
+               unsigned long blkcount;
+               uint8_t diskbuf[MAXBSIZE];
+       } level[LEVELS];
+
+       assert(params != NULL);
+       assert(params->fstype != NULL);
+       assert(callback != NULL);
+       assert(state != NULL);
+
+       /* Read the superblock. */
+       fs = (void *)sbbuf;
+       if (ext2fs_read_sblock(params, fs) == 0)
+               return 0;
+
+       fs->e2fs_gd = malloc(sizeof(struct ext2_gd) * fs->e2fs_ncg);
+       if (fs->e2fs_gd == NULL) {
+               warnx("Can't allocate memofy for group descriptors");
+               return 0;
+       }
+
+       if (ext2fs_read_gdblock(params, fs) == 0) {
+               warnx("Can't read group descriptors");
+               return 0;
+       }
+
+       if (fs->e2fs_ipb <= 0) {
+               warnx("Bad ipb %d in superblock in `%s'",
+                   fs->e2fs_ipb, params->filesystem);
+               return 0;
+       }
+
+       /* Read the inode. */
+       if (ext2fs_read_disk_block(params,
+               fsbtodb(fs, ino_to_fsba(fs, ino)) + params->fstype->offset,
+               fs->e2fs_bsize, inodebuf))
+               return 0;
+       inode = (void *)inodebuf;
+       e2fs_iload(&inode[ino_to_fsbo(fs, ino)], &inode_store);
+       inode = &inode_store;
+
+       /* Get the block count and initialize for our block walk. */
+       nblk = howmany(inode->e2di_size, fs->e2fs_bsize);
+       lblk = 0;
+       level_i = 0;
+       level[0].blknums = &inode->e2di_blocks[0];
+       level[0].blkcount = NDADDR;
+       level[1].blknums = &inode->e2di_blocks[NDADDR + 0];
+       level[1].blkcount = 1;
+       level[2].blknums = &inode->e2di_blocks[NDADDR + 1];
+       level[2].blkcount = 1;
+       level[3].blknums = &inode->e2di_blocks[NDADDR + 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 = fs2h32(*(level[level_i].blknums++));
+               level[level_i].blkcount--;
+
+#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 (ext2fs_read_disk_block(params, 
+                               fsbtodb(fs, blk) + params->fstype->offset,
+                               fs->e2fs_bsize, level[level_i].diskbuf) == 0)
+                               return 0;
+                       /* XXX ondisk32 */
+                       level[level_i].blknums = 
+                           (uint32_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), sblksize(fs, inode->di_size, lblk));
+#endif
+               rv = (*callback)(params, state, 
+                   fsbtodb(fs, blk) + params->fstype->offset, fs->e2fs_bsize);
+               lblk++;
+               nblk--;
+               if (rv != 1)
+                       return rv;
+       }
+
+       if (nblk != 0) {
+               warnx("Inode %llu in `%s' ran out of blocks?",
+                   (unsigned long long)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
+ext2fs_findstage2_ino(ib_params *params, void *_ino, 
+       uint64_t blk, uint32_t blksize)
+{
+       uint8_t dirbuf[MAXBSIZE];
+       struct ext2fs_direct *de, *ede;
+       uint32_t ino;
+
+       assert(params != NULL);
+       assert(params->fstype != NULL);
+       assert(params->stage2 != NULL);
+       assert(_ino != NULL);
+
+       /* Skip directory holes. */
+       if (blk == 0)
+               return 1;
+
+       /* Read the directory block. */
+       if (ext2fs_read_disk_block(params, blk, blksize, dirbuf) == 0)
+               return 0;
+
+       /* Loop over the directory entries. */
+       de = (struct ext2fs_direct *)&dirbuf[0];
+       ede = (struct ext2fs_direct *)&dirbuf[blksize];
+       while (de < ede) {
+               ino = fs2h32(de->e2d_ino);
+               if (ino != 0 && strcmp(de->e2d_name, params->stage2) == 0) {
+                       *((uint32_t *)_ino) = ino;
+                       return (2);
+               }
+               if (fs2h16(de->e2d_reclen) == 0)
+                       break;
+               de = (struct ext2fs_direct *)((char *)de +
+                   fs2h16(de->e2d_reclen));
+       }
+
+       return 1;
+}
+
+struct findblks_state {
+       uint32_t        maxblk;
+       uint32_t        nblk;
+       ib_block        *blocks;
+};
+
+/* This callback records the blocks of the secondary bootstrap. */
+static int
+ext2fs_findstage2_blocks(ib_params *params, void *_state,
+       uint64_t blk, uint32_t blksize)
+{
+       struct findblks_state *state = _state;
+
+       assert(params != NULL);
+       assert(params->stage2 != NULL);
+       assert(_state != NULL);
+
+       if (state->nblk == state->maxblk) {
+               warnx("Secondary bootstrap `%s' has too many blocks (max %d)",
+                   params->stage2, state->maxblk);
+               return (0);
+       }
+       state->blocks[state->nblk].block = blk;
+       state->blocks[state->nblk].blocksize = blksize;
+       state->nblk++;
+       return 1;
+}
+
+/*
+ *     publicly visible functions
+ */
+
+int
+ext2fs_match(ib_params *params)
+{
+       uint8_t sbbuf[sizeof(struct m_ext2fs)];
+       struct m_ext2fs *fs;
+
+       assert(params != NULL);
+       assert(params->fstype != NULL);
+
+       /* Read the superblock. */
+       fs = (void *)sbbuf;
+       if (ext2fs_read_sblock(params, fs) == 0)
+               return 0;
+
+       params->fstype->needswap = 0;
+       params->fstype->blocksize = fs->e2fs_bsize;
+       params->fstype->offset = 0;
+
+       return 1;
+}
+
+int
+ext2fs_findstage2(ib_params *params, uint32_t *maxblk, ib_block *blocks)
+{
+       int rv;
+       uint32_t ino;
+       struct findblks_state state;
+
+       assert(params != NULL);
+       assert(params->stage2 != NULL);
+       assert(maxblk != NULL);
+       assert(blocks != NULL);
+
+       if (params->flags & IB_STAGE2START)
+               return hardcode_stage2(params, maxblk, blocks);
+
+       /* 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);
+               warnx("(Path must be relative to the file system in `%s')",
+                   params->filesystem);
+               return 0;
+       }
+
+       /* Get the inode number of the secondary bootstrap. */
+       rv = ext2fs_find_disk_blocks(params, EXT2_ROOTINO,
+           ext2fs_findstage2_ino, &ino);
+       if (rv != 2) {
+               warnx("Could not find secondary bootstrap `%s' in `%s'",
+                   params->stage2, params->filesystem);
+               warnx("(Path must be relative to the file system in `%s')",
+                   params->filesystem);
+               return 0;
+       }
+
+       /* Record the disk blocks of the secondary bootstrap. */
+       state.maxblk = *maxblk;
+       state.nblk = 0;
+       state.blocks = blocks;
+               rv = ext2fs_find_disk_blocks(params, ino,
+                   ext2fs_findstage2_blocks, &state);
+       if (rv == 0)
+               return 0;
+
+       *maxblk = state.nblk;
+       return 1;
+}
diff --git a/usr.sbin/installboot/ffs.c b/usr.sbin/installboot/ffs.c
new file mode 100644 (file)
index 0000000..178eb97
--- /dev/null
@@ -0,0 +1,592 @@
+/*     $NetBSD: ffs.c,v 1.29 2010/01/14 16:27:49 tsutsui Exp $ */
+
+/*-
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: ffs.c,v 1.29 2010/01/14 16:27:49 tsutsui Exp $");
+#endif /* !__lint */
+
+#include <sys/param.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 "installboot.h"
+
+/* From <dev/raidframe/raidframevar.h> */
+#define RF_PROTECTED_SECTORS 64L
+
+#undef DIRBLKSIZ
+
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ffs/fs.h>
+#include <ufs/ffs/ffs_extern.h>
+#ifndef NO_FFS_SWAP
+#include <ufs/ufs/ufs_bswap.h>
+#else
+#define        ffs_sb_swap(fs_a, fs_b)
+#define        ffs_dinode1_swap(inode_a, inode_b)
+#define        ffs_dinode2_swap(inode_a, inode_b)
+#endif
+
+static int     ffs_match_common(ib_params *, off_t);
+static int     ffs_read_disk_block(ib_params *, uint64_t, int, char []);
+static int     ffs_find_disk_blocks_ufs1(ib_params *, ino_t,
+                   int (*)(ib_params *, void *, uint64_t, uint32_t), void *);
+static int     ffs_find_disk_blocks_ufs2(ib_params *, ino_t,
+                   int (*)(ib_params *, void *, uint64_t, uint32_t), void *);
+static int     ffs_findstage2_ino(ib_params *, void *, uint64_t, uint32_t);
+static int     ffs_findstage2_blocks(ib_params *, void *, uint64_t, uint32_t);
+
+static int is_ufs2;
+
+
+/* This reads a disk block from the filesystem. */
+static int
+ffs_read_disk_block(ib_params *params, uint64_t blkno, int size, char blk[])
+{
+       int     rv;
+
+       assert(params != NULL);
+       assert(params->filesystem != NULL);
+       assert(params->fsfd != -1);
+       assert(size > 0);
+       assert(blk != NULL);
+
+       rv = pread(params->fsfd, blk, size, blkno * params->sectorsize);
+       if (rv == -1) {
+               warn("Reading block %llu in `%s'", 
+                   (unsigned long long)blkno, params->filesystem);
+               return (0);
+       } else if (rv != size) {
+               warnx("Reading block %llu in `%s': short read",
+                   (unsigned long long)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_ufs1(ib_params *params, ino_t ino, 
+       int (*callback)(ib_params *, void *, uint64_t, uint32_t),
+       void *state)
+{
+       char            sbbuf[SBLOCKSIZE];
+       struct fs       *fs;
+       char            inodebuf[MAXBSIZE];
+       struct ufs1_dinode      *inode;
+       int             level_i;
+       int32_t blk, lblk, nblk;
+       int             rv;
+#define LEVELS 4
+       struct {
+               int32_t         *blknums;
+               unsigned long   blkcount;
+               char            diskbuf[MAXBSIZE];
+       } level[LEVELS];
+
+       assert(params != NULL);
+       assert(params->fstype != NULL);
+       assert(callback != NULL);
+       assert(state != NULL);
+
+       /* Read the superblock. */
+       if (!ffs_read_disk_block(params, params->fstype->sblockloc, SBLOCKSIZE,
+           sbbuf))
+               return (0);
+       fs = (struct fs *)sbbuf;
+#ifndef NO_FFS_SWAP
+       if (params->fstype->needswap)
+               ffs_sb_swap(fs, fs);
+#endif
+
+       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)) + params->fstype->offset,
+               fs->fs_bsize, inodebuf))
+               return (0);
+       inode = (struct ufs1_dinode *)inodebuf;
+       inode += ino_to_fsbo(fs, ino);
+#ifndef NO_FFS_SWAP
+       if (params->fstype->needswap)
+               ffs_dinode1_swap(inode, inode);
+#endif
+
+       /* 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 (params->fstype->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) + params->fstype->offset,
+                               fs->fs_bsize, level[level_i].diskbuf))
+                               return (0);
+                       /* XXX ondisk32 */
+                       level[level_i].blknums = 
+                               (int32_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), sblksize(fs, inode->di_size, lblk));
+#endif
+               rv = (*callback)(params, state, 
+                   fsbtodb(fs, blk) + params->fstype->offset,
+                   sblksize(fs, (int64_t)inode->di_size, lblk));
+               lblk++;
+               nblk--;
+               if (rv != 1)
+                       return (rv);
+       }
+
+       if (nblk != 0) {
+               warnx("Inode %llu in `%s' ran out of blocks?",
+                   (unsigned long long)ino, 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_ufs2(ib_params *params, ino_t ino, 
+       int (*callback)(ib_params *, void *, uint64_t, uint32_t),
+       void *state)
+{
+       char            sbbuf[SBLOCKSIZE];
+       struct fs       *fs;
+       char            inodebuf[MAXBSIZE];
+       struct ufs2_dinode      *inode;
+       int             level_i;
+       int64_t         blk, lblk, nblk;
+       int             rv;
+#define LEVELS 4
+       struct {
+               int64_t         *blknums;
+               unsigned long   blkcount;
+               char            diskbuf[MAXBSIZE];
+       } level[LEVELS];
+
+       assert(params != NULL);
+       assert(params->fstype != NULL);
+       assert(callback != NULL);
+       assert(state != NULL);
+
+       /* Read the superblock. */
+       if (!ffs_read_disk_block(params, params->fstype->sblockloc, SBLOCKSIZE,
+           sbbuf))
+               return (0);
+       fs = (struct fs *)sbbuf;
+#ifndef NO_FFS_SWAP
+       if (params->fstype->needswap)
+               ffs_sb_swap(fs, fs);
+#endif
+
+       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)) + params->fstype->offset,
+               fs->fs_bsize, inodebuf))
+               return (0);
+       inode = (struct ufs2_dinode *)inodebuf;
+       inode += ino_to_fsbo(fs, ino);
+#ifndef NO_FFS_SWAP
+       if (params->fstype->needswap)
+               ffs_dinode2_swap(inode, inode);
+#endif
+
+       /* 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 (params->fstype->needswap)
+                       blk = bswap64(blk);
+
+#if 0
+               fprintf(stderr, "ino %lu blk %llu level %d\n", ino,
+                   (unsigned long long)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) + params->fstype->offset,
+                               fs->fs_bsize, level[level_i].diskbuf))
+                               return (0);
+                       level[level_i].blknums = 
+                               (int64_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 %llu blksize %lu\n", ino, 
+                   fsbtodb(fs, blk), sblksize(fs, inode->di_size, lblk));
+#endif
+               rv = (*callback)(params, state, 
+                   fsbtodb(fs, blk) + params->fstype->offset,
+                   sblksize(fs, (int64_t)inode->di_size, lblk));
+               lblk++;
+               nblk--;
+               if (rv != 1)
+                       return (rv);
+       }
+
+       if (nblk != 0) {
+               warnx("Inode %llu in `%s' ran out of blocks?",
+                   (unsigned long long)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, 
+       uint64_t blk, uint32_t blksize)
+{
+       char            dirbuf[MAXBSIZE];
+       struct direct   *de, *ede;
+       uint32_t        ino;
+
+       assert(params != NULL);
+       assert(params->fstype != NULL);
+       assert(params->stage2 != NULL);
+       assert(_ino != NULL);
+
+       /* 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_fileno;
+               if (params->fstype->needswap) {
+                       ino = bswap32(ino);
+                       de->d_reclen = bswap16(de->d_reclen);
+               }
+               if (ino != 0 && strcmp(de->d_name, params->stage2) == 0) {
+                       *((uint32_t *)_ino) = ino;
+                       return (2);
+               }
+               if (de->d_reclen == 0)
+                       break;
+               de = (struct direct *)((char *)de + de->d_reclen);
+       }
+
+       return (1);
+}
+
+struct findblks_state {
+       uint32_t        maxblk;
+       uint32_t        nblk;
+       ib_block        *blocks;
+};
+
+/* This callback records the blocks of the secondary bootstrap. */
+static int
+ffs_findstage2_blocks(ib_params *params, void *_state,
+       uint64_t blk, uint32_t blksize)
+{
+       struct findblks_state *state = _state;
+
+       assert(params != NULL);
+       assert(params->stage2 != NULL);
+       assert(_state != NULL);
+
+       if (state->nblk == state->maxblk) {
+               warnx("Secondary bootstrap `%s' has too many blocks (max %d)",
+                   params->stage2, state->maxblk);
+               return (0);
+       }
+       state->blocks[state->nblk].block = blk;
+       state->blocks[state->nblk].blocksize = blksize;
+       state->nblk++;
+       return (1);
+}
+
+/*
+ *     publicly visible functions
+ */
+
+static off_t sblock_try[] = SBLOCKSEARCH;
+
+int
+ffs_match(ib_params *params)
+{
+       return ffs_match_common(params, (off_t) 0);
+}
+
+int
+raid_match(ib_params *params)
+{
+       /* XXX Assumes 512 bytes / sector */
+       if (params->sectorsize != 512) {
+               warnx("Media is %d bytes/sector."
+                       "  RAID is only supported on 512 bytes/sector media.",
+                       params->sectorsize);
+               return 0;
+       }
+       return ffs_match_common(params, (off_t) RF_PROTECTED_SECTORS);
+}
+
+int
+ffs_match_common(ib_params *params, off_t offset)
+{
+       char            sbbuf[SBLOCKSIZE];
+       struct fs       *fs;
+       int i;
+       off_t loc;
+
+       assert(params != NULL);
+       assert(params->fstype != NULL);
+
+       fs = (struct fs *)sbbuf;
+       for (i = 0; sblock_try[i] != -1; i++) {
+               loc = sblock_try[i] / params->sectorsize + offset;
+               if (!ffs_read_disk_block(params, loc, SBLOCKSIZE, sbbuf))
+                       continue;
+               switch (fs->fs_magic) {
+               case FS_UFS2_MAGIC:
+                       is_ufs2 = 1;
+                       /* FALLTHROUGH */
+               case FS_UFS1_MAGIC:
+                       params->fstype->needswap = 0;
+                       params->fstype->blocksize = fs->fs_bsize;
+                       params->fstype->sblockloc = loc;
+                       params->fstype->offset = offset;
+                       break;
+#ifndef FFS_NO_SWAP
+               case FS_UFS2_MAGIC_SWAPPED:
+                       is_ufs2 = 1;
+                       /* FALLTHROUGH */
+               case FS_UFS1_MAGIC_SWAPPED:
+                       params->fstype->needswap = 1;
+                       params->fstype->blocksize = bswap32(fs->fs_bsize);
+                       params->fstype->sblockloc = loc;
+                       params->fstype->offset = offset;
+                       break;
+#endif
+               default:
+                       continue;
+               }
+               if (!is_ufs2 && sblock_try[i] == SBLOCK_UFS2)
+                       continue;
+               return 1;
+       }
+
+       return (0);
+}
+
+int
+ffs_findstage2(ib_params *params, uint32_t *maxblk, ib_block *blocks)
+{
+       int                     rv;
+       uint32_t                ino;
+       struct findblks_state   state;
+
+       assert(params != NULL);
+       assert(params->stage2 != NULL);
+       assert(maxblk != NULL);
+       assert(blocks != NULL);
+
+       if (params->flags & IB_STAGE2START)
+               return (hardcode_stage2(params, maxblk, blocks));
+
+       /* 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);
+               warnx("(Path must be relative to the file system in `%s')",
+                   params->filesystem);
+               return (0);
+       }
+
+       /* Get the inode number of the secondary bootstrap. */
+       if (is_ufs2)
+               rv = ffs_find_disk_blocks_ufs2(params, ROOTINO,
+                   ffs_findstage2_ino, &ino);
+       else
+               rv = ffs_find_disk_blocks_ufs1(params, ROOTINO,
+                   ffs_findstage2_ino, &ino);
+       if (rv != 2) {
+               warnx("Could not find secondary bootstrap `%s' in `%s'",
+                   params->stage2, params->filesystem);
+               warnx("(Path must be relative to the file system in `%s')",
+                   params->filesystem);
+               return (0);
+       }
+
+       /* Record the disk blocks of the secondary bootstrap. */
+       state.maxblk = *maxblk;
+       state.nblk = 0;
+       state.blocks = blocks;
+       if (is_ufs2)
+               rv = ffs_find_disk_blocks_ufs2(params, ino,
+                   ffs_findstage2_blocks, &state);
+       else
+               rv = ffs_find_disk_blocks_ufs1(params, ino,
+                   ffs_findstage2_blocks, &state);
+       if (! rv) {
+               return (0);
+       }
+
+       *maxblk = state.nblk;
+       return (1);
+}
diff --git a/usr.sbin/installboot/fstypes.c b/usr.sbin/installboot/fstypes.c
new file mode 100644 (file)
index 0000000..1b77f97
--- /dev/null
@@ -0,0 +1,133 @@
+/*     $NetBSD: fstypes.c,v 1.13 2010/01/14 16:27:49 tsutsui Exp $     */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Fredette and Luke Mewburn.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: fstypes.c,v 1.13 2010/01/14 16:27:49 tsutsui Exp $");
+#endif /* !__lint */
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <err.h>
+#include <stdio.h>
+
+#include "installboot.h"
+
+struct ib_fs fstypes[] = {
+#ifndef NO_STAGE2
+       { .name = "ffs",  .match = ffs_match,   .findstage2 = ffs_findstage2    },
+       { .name = "raid", .match = raid_match,  .findstage2 = ffs_findstage2    },
+       { .name = "raw",  .match = raw_match,   .findstage2 = raw_findstage2    },
+#endif
+       { .name = NULL, }
+};
+
+#ifndef NO_STAGE2
+int
+hardcode_stage2(ib_params *params, uint32_t *maxblk, ib_block *blocks)
+{
+       struct stat     s2sb;
+       uint32_t        nblk, i;
+
+       assert(params != NULL);
+       assert(params->stage2 != NULL);
+       assert(maxblk != NULL);
+       assert(blocks != NULL);
+       assert((params->flags & IB_STAGE2START) != 0);
+       assert(params->fstype != NULL);
+       assert(params->fstype->blocksize != 0);
+
+       if (stat(params->stage2, &s2sb) == -1) {
+               warn("Examining `%s'", params->stage2);
+               return (0);
+       }
+       if (!S_ISREG(s2sb.st_mode)) {
+               warnx("`%s' must be a regular file", params->stage2);
+               return (0);
+       }
+
+       nblk = s2sb.st_size / params->fstype->blocksize;
+       if (s2sb.st_size % params->fstype->blocksize != 0)
+               nblk++;
+#if 0
+       fprintf(stderr, "for %s got size %lld blksize %u blocks %u\n",
+           params->stage2, s2sb.st_size, params->fstype->blocksize, nblk);
+#endif
+       if (nblk > *maxblk) {
+                warnx("Secondary bootstrap `%s' has too many blocks "
+                    "(calculated %u, maximum %u)",
+                   params->stage2, nblk, *maxblk);
+                return (0);
+        }
+
+       for (i = 0; i < nblk; i++) {
+               blocks[i].block = params->s2start +
+                   i * (params->fstype->blocksize / params->sectorsize);
+               blocks[i].blocksize = params->fstype->blocksize;
+       }
+       *maxblk = nblk;
+
+       return (1);
+}
+
+
+int
+raw_match(ib_params *params)
+{
+
+       assert(params != NULL);
+       assert(params->fstype != NULL);
+
+       params->fstype->blocksize = 8192;               // XXX: hardcode
+       return (1);             /* can always write to a "raw" file system */
+}
+
+int
+raw_findstage2(ib_params *params, uint32_t *maxblk, ib_block *blocks)
+{
+
+       assert(params != NULL);
+       assert(params->stage2 != NULL);
+       assert(maxblk != NULL);
+       assert(blocks != NULL);
+
+       if ((params->flags & IB_STAGE2START) == 0) {
+               warnx("Need `-B bno' for raw file systems");
+               return (0);
+       }
+       return (hardcode_stage2(params, maxblk, blocks));
+}
+#endif
diff --git a/usr.sbin/installboot/installboot.8 b/usr.sbin/installboot/installboot.8
new file mode 100644 (file)
index 0000000..cab63aa
--- /dev/null
@@ -0,0 +1,895 @@
+.\"    $NetBSD: installboot.8,v 1.79 2011/11/03 20:09:18 martin Exp $
+.\"
+.\" Copyright (c) 2002-2009 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.
+.\"
+.\" 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.
+.\"
+.Dd August 3, 2011
+.Dt INSTALLBOOT 8
+.Os
+.Sh NAME
+.Nm installboot
+.Nd install disk bootstrap software
+.
+.Sh SYNOPSIS
+.Nm
+.Op Fl fnv
+.Op Fl B Ar s2bno
+.Op Fl b Ar s1bno
+.Op Fl m Ar machine
+.Op Fl o Ar options
+.Op Fl t Ar fstype
+.Ar filesystem
+.Ar primary
+.Op Ar secondary
+.Nm
+.Fl c
+.Op Fl fnv
+.Op Fl m Ar machine
+.Op Fl o Ar options
+.Op Fl t Ar fstype
+.Ar filesystem
+.Nm
+.Fl e
+.Op Fl fnv
+.Op Fl m Ar machine
+.Op Fl o Ar options
+.Ar bootstrap
+.
+.Sh DESCRIPTION
+The
+.Nm
+utility installs and removes
+.Nx
+disk bootstrap software into a file system.
+.Nm
+can install
+.Ar primary
+into
+.Ar filesystem ,
+or disable an existing bootstrap in
+.Ar filesystem .
+.Pp
+On some architectures the options of an existing installed bootstrap,
+or those of a bootstrap file can be changed.
+Installing a new primary bootstrap will reset those options to default
+values.
+.Pp
+Generally,
+.Nx
+disk bootstrap software consists of two parts: a
+.Dq primary
+bootstrap program usually written into the disklabel area of the
+file system by
+.Nm ,
+and a
+.Dq secondary
+bootstrap program that usually resides as an ordinary file in the file system.
+.Pp
+When booting, the primary bootstrap program is loaded and invoked by
+the machine's PROM or BIOS.
+After receiving control of the system it loads and runs the secondary
+bootstrap program, which in turn loads and runs the kernel.
+The secondary bootstrap may allow control over various boot parameters
+passed to the kernel.
+.Pp
+Perform the following steps to make a file system bootable:
+.Bl -enum
+.It
+Copy the secondary bootstrap (usually
+.Pa /usr/mdec/boot. Ns Sy MACHINE
+or
+.Pa /usr/mdec/boot )
+to the root directory of the target file system.
+.Pp
+.
+.It
+Use
+.Nm
+to install the primary bootstrap program
+(usually
+.Pa /usr/mdec/bootxx_ Ns Sy FSTYPE )
+into
+.Ar filesystem .
+.Pp
+The following platforms do not require this step if the primary bootstrap
+already exists and the secondary bootstrap file is just being updated:
+.Sy alpha ,
+.Sy amd64 ,
+.Sy amiga ,
+.Sy i386 ,
+.Sy pmax ,
+.Sy sparc64 ,
+and
+.Sy vax .
+.Pp
+The following platform does not require the first step since a
+single bootstrap file is used.
+The single bootstrap is installed like the primary bootstrap on
+other platforms:
+.Sy next68k .
+.Pp
+.El
+.Pp
+The options and arguments recognized by
+.Nm
+are as follows:
+.
+.Bl -tag -width "optionsxxx"
+.
+.It Fl B Ar s2bno
+When hard-coding the blocks of
+.Ar secondary
+into
+.Ar primary ,
+start from block
+.Ar s2bno
+instead of trying to determine the block numbers occupied by
+.Ar secondary
+by examining
+.Ar filesystem .
+If this option is supplied,
+.Ar secondary
+should refer to an actual secondary bootstrap (rather than the
+file name of the one present in
+.Ar filesystem )
+so that its size can be determined.
+.
+.It Fl b Ar s1bno
+Install
+.Ar primary
+at block number
+.Ar s1bno
+instead of the default location for the machine and file system type.
+.Sy [ alpha ,
+.Sy pmax ,
+.Sy vax ]
+.
+.It Fl c
+Clear (remove) any existing bootstrap instead of installing one.
+.
+.It Fl e
+Edit the options of an existing bootstrap.
+This can be use to change the options in bootxx_xxxfs files,
+raw disk partitions, and the
+.Pa pxeboot_ia32.bin
+file.
+With
+.Fl v
+and without
+.Fl o ,
+show the current options.
+.Sy [ amd64 , i386 ]
+.
+.It Fl f
+Forces
+.Nm
+to ignore some errors.
+.
+.It Fl m Ar machine
+Use
+.Ar machine
+as the target machine type.
+The default machine is determined from
+.Xr uname 3
+and then
+.Ev MACHINE .
+The following machines are currently supported by
+.Nm :
+.Bd -ragged -offset indent
+.Sy alpha ,
+.Sy amd64 ,
+.Sy amiga ,
+.Sy ews4800mips ,
+.Sy hp300 ,
+.Sy hp700 ,
+.Sy i386 ,
+.Sy landisk ,
+.Sy macppc ,
+.Sy news68k ,
+.Sy newsmips ,
+.Sy next68k ,
+.Sy pmax ,
+.Sy sparc ,
+.Sy sparc64 ,
+.Sy sun2 ,
+.Sy sun3 ,
+.Sy vax ,
+.Sy x68k
+.Ed
+.
+.
+.It Fl n
+Do not write to
+.Ar filesystem .
+.
+.It Fl o Ar options
+Machine specific
+.Nm
+options, comma separated.
+.Pp
+Supported options are (with the machines for they are valid in brackets):
+.
+.Bl -tag -offset indent -width alphasum
+.
+.It Sy alphasum
+.Sy [ alpha ]
+Recalculate and restore the Alpha checksum.
+This is the default for
+.Nx Ns Tn /alpha .
+.
+.It Sy append
+.Sy [ alpha ,
+.Sy pmax ,
+.Sy vax ]
+Append
+.Ar primary
+to the end of
+.Ar filesystem ,
+which must be a regular file in this case.
+.
+.It Sy bootconf
+.Sy [ amd64 ,
+.Sy i386 ]
+(Don't) read a
+.Dq boot.cfg
+file.
+.
+.It Sy command=\*[Lt]boot command\*[Gt]
+.Sy [ amiga ]
+Modify the default boot command line.
+.
+.It Sy console=\*[Lt]console name\*[Gt]
+.Sy [ amd64 ,
+.Sy i386 ]
+Set the console device, \*[Lt]console name\*[Gt] must be one of:
+pc, com0, com1, com2, com3, com0kbd, com1kbd, com2kbd or com3kbd.
+.
+.It Sy ioaddr=\*[Lt]ioaddr\*[Gt]
+.Sy [ amd64 ,
+.Sy i386 ]
+Set the IO address to be used for the console serial port.
+Defaults to the IO address used by the system BIOS for the specified port.
+.
+.It Sy keymap=\*[Lt]keymap\*[Gt]
+.Sy [ amd64 ,
+.Sy i386 ]
+Set a boot time keyboard translation map.
+Each character in \*[Lt]keymap\*[Gt] will be replaced by the one following it.
+For example, an argument of
+.Dq zyz
+would swap the lowercase letters
+.Sq y
+and
+.Sq z .
+.
+.It Sy modules
+.Sy [ amd64 ,
+.Sy i386 ]
+(Don't) load kernel modules.
+.
+.It Sy password=\*[Lt]password\*[Gt]
+.Sy [ amd64 ,
+.Sy i386 ]
+Set the password which must be entered before the boot menu can be accessed.
+.
+.It Sy resetvideo
+.Sy [ amd64 ,
+.Sy i386 ]
+Reset the video before booting.
+.
+.It Sy speed=\*[Lt]baud rate\*[Gt]
+.Sy [ amd64 ,
+.Sy i386 ]
+Set the baud rate for the serial console.
+If a value of zero is specified, then the current baud rate (set by the
+BIOS) will be used.
+.
+.It Sy sunsum
+.Sy [ alpha ,
+.Sy pmax ,
+.Sy vax ]
+Recalculate and restore the Sun and
+.Nx Ns Tn /sparc
+compatible checksum.
+.Em Note :
+The existing
+.Nx Ns Tn /sparc
+disklabel should use no more than 4 partitions.
+.
+.It Sy timeout=\*[Lt]seconds\*[Gt]
+.Sy [ amd64 ,
+.Sy i386 ]
+Set the timeout before the automatic boot begins to the given number of seconds.
+.El
+.
+.It Fl t Ar fstype
+Use
+.Ar fstype
+as the type of
+.Ar filesystem .
+The default operation is to attempt to auto-detect this setting.
+The following file system types are currently supported by
+.Nm :
+.
+.Bl -tag -offset indent -width raid
+.
+.It Sy ffs
+.Bx
+Fast File System.
+.
+.It Sy raid
+Mirrored RAIDframe File System.
+.
+.It Sy raw
+.Sq Raw
+image.
+Note: if a platform needs to hard-code the block offset of the secondary
+bootstrap, it cannot be searched for on this file system type, and must
+be provided with
+.Fl B Ar s2bno .
+.El
+.
+.It Fl v
+Verbose operation.
+.
+.It Ar filesystem
+The path name of the device or file system image that
+.Nm
+is to operate on.
+It is not necessary for
+.Ar filesystem
+to be a currently mounted file system.
+.
+.It Ar primary
+The path name of the
+.Dq primary
+boot block to install.
+The path name must refer to a file in a file system that is currently
+mounted.
+.
+.It Ar secondary
+The path name of the
+.Dq secondary
+boot block, relative to the root of
+the file system in the device or image specified by the
+.Ar filesystem
+argument.
+Note that this may refer to a file in a file system that is not mounted.
+Most systems require
+.Ar secondary
+to be in the
+.Dq root
+directory of the file system, so the leading
+.Dq Pa /
+is not necessary on
+.Ar secondary .
+.Pp
+Only certain combinations of
+platform
+.Pq Fl m Ar machine
+and file system type
+.Pq Fl t Ar fstype
+require that the name of the secondary bootstrap is
+supplied as
+.Ar secondary ,
+so that information such as the disk block numbers occupied
+by the secondary bootstrap can be stored in the primary bootstrap.
+These are:
+.Bl -column "Platform" "File systems" -offset indent
+.It Sy "Platform" Ta Sy "File systems"
+.It macppc Ta ffs, raw
+.It news68k Ta ffs, raw
+.It newsmips Ta ffs, raw
+.It sparc Ta ffs, raid, raw
+.It sun2 Ta ffs, raw
+.It sun3 Ta ffs, raw
+.El
+.El
+.Pp
+.Nm
+exits 0 on success, and \*[Gt]0 if an error occurs.
+.
+.Sh ENVIRONMENT
+.Nm
+uses the following environment variables:
+.
+.Bl -tag -width "MACHINE"
+.
+.It Ev MACHINE
+Default value for
+.Ar machine ,
+overriding the result from
+.Xr uname 3 .
+.
+.El
+.
+.Sh FILES
+Most
+.Nx
+ports will contain variations of the following files:
+.Pp
+.Bl -tag -width /usr/mdec/bootxx_ustarfs
+.
+.It Pa /usr/mdec/bootxx_ Ns Sy FSTYPE
+Primary bootstrap for file system type
+.Sy FSTYPE .
+Installed into the bootstrap area of the file system by
+.Nm .
+.
+.It Pa /usr/mdec/bootxx_fat16
+Primary bootstrap for
+.Tn MS-DOS
+.Sy FAT16
+file systems.
+This differs from
+.Nm bootxx_msdos
+in that it doesn't require the filesystem to have been initialised with
+any
+.Ql reserved sectors .
+It also uses the information in the
+.Ql Boot Parameter Block
+to get the media and filesytem properties.
+.
+.It Pa /usr/mdec/bootxx_ffsv1
+Primary bootstrap for
+.Sy FFSv1
+file systems
+(the "traditional"
+.Nx
+file system).
+Use
+.Xr dumpfs 8
+to confirm the file system format is
+.Sy FFSv1 .
+.
+.It Pa /usr/mdec/bootxx_ffsv2
+Primary bootstrap for
+.Sy FFSv2
+file systems.
+Use
+.Xr dumpfs 8
+to confirm the file system format is
+.Sy FFSv2 .
+.
+.It Pa /usr/mdec/bootxx_lfsv1
+Primary bootstrap for
+.Sy LFSv1
+file systems.
+.
+.It Pa /usr/mdec/bootxx_lfsv2
+Primary bootstrap for
+.Sy LFSv2
+file systems
+(the default LFS version).
+.
+.It Pa /usr/mdec/bootxx_msdos
+Primary bootstrap for
+.Tn MS-DOS
+.Sy FAT
+file systems.
+.
+.It Pa /usr/mdec/bootxx_ustarfs
+Primary bootstrap for
+.Sy TARFS
+boot images.
+This is used by various install media.
+.
+.It Pa /usr/mdec/boot. Ns Sy MACHINE
+Secondary bootstrap for machine type
+.Sy MACHINE .
+This should be installed into the file system before
+.Nm
+is run.
+.
+.It Pa /usr/mdec/boot
+Synonym for
+.Pa /usr/mdec/boot. Ns Sy MACHINE
+.
+.It Pa /boot. Ns Sy MACHINE
+Installed copy of secondary bootstrap for machine type
+.Sy MACHINE .
+.
+.It Pa /boot
+Installed copy of secondary bootstrap.
+Searched for by the primary bootstrap if
+.Pa /boot. Ns Sy MACHINE
+is not found.
+.
+.El
+.
+.Ss Nx Ns Tn /macppc files
+.
+.Bl -tag -width /usr/mdec/bootxx_ustarfs
+.
+.It Pa /usr/mdec/bootxx
+.Nx Ns Tn /macppc
+primary bootstrap.
+.
+.It Pa /usr/mdec/ofwboot
+.Nx Ns Tn /macppc
+secondary bootstrap.
+.
+.It Pa /ofwboot
+Installed copy of
+.Nx Ns Tn /macppc
+secondary bootstrap.
+.
+.El
+.
+.Ss Nx Ns Tn /next68k files
+.
+.Bl -tag -width /usr/mdec/bootxx_ustarfs
+.
+.It Pa /usr/mdec/boot
+.Nx Ns Tn /next68k
+bootstrap.
+.
+.El
+.
+.Ss Nx Ns Tn /sparc64 files
+.
+.Bl -tag -width /usr/mdec/bootxx_ustarfs
+.
+.It Pa /usr/mdec/bootblk
+.Nx Ns Tn /sparc64
+primary bootstrap.
+.
+.It Pa /usr/mdec/ofwboot
+.Nx Ns Tn /sparc64
+secondary bootstrap.
+.
+.It Pa /ofwboot
+Installed copy of
+.Nx Ns Tn /sparc64
+secondary bootstrap.
+.
+.El
+.
+.Sh EXAMPLES
+.
+.Ss common
+Verbosely install the Berkeley Fast File System primary bootstrap on to disk
+.Sq sd0 :
+.Dl Ic installboot -v /dev/rsd0c /usr/mdec/bootxx_ffs
+Note: the
+.Dq whole disk
+partition (c on some ports, d on others) is used here, since the a partition
+probably is already opened (mounted as
+.Pa / ) ,
+so
+.Nm
+would not be able to access it.
+.Pp
+Remove the primary bootstrap from disk
+.Sq sd1 :
+.Dl Ic installboot -c /dev/rsd1c
+.
+.Ss Nx Ns Tn /amiga
+Modify the command line to change the default from "netbsd -ASn2" to
+"netbsd -S":
+.Dl Ic installboot -m amiga -o command="netbsd -S" /dev/rsd0a /usr/mdec/bootxx_ffs
+.
+.Ss Nx Ns Tn /ews4800mips
+Install the System V Boot File System primary bootstrap on to disk
+.Sq sd0 ,
+with the secondary bootstrap
+.Sq Pa /boot
+already present in the SysVBFS partition on the disk:
+.Dl Ic installboot /dev/rsd0c /usr/mdec/bootxx_bfs
+.
+.Ss Nx Ns Tn /i386 and Nx Ns Tn /amd64
+Install new boot blocks on an existing mounted root file system on
+.Sq wd0 ,
+setting the timeout to five seconds, after copying a new secondary
+bootstrap:
+.Dl Ic cp /usr/mdec/boot /boot
+.Dl Ic installboot -v -o timeout=5 /dev/rwd0a /usr/mdec/bootxx_ffsv1
+.
+.Pp
+Create a bootable CD-ROM with an ISO9660
+file system for an i386 system with a serial console:
+.Dl Ic mkdir cdrom
+.Dl Ic cp sys/arch/i386/compile/mykernel/netbsd cdrom/netbsd
+.Dl Ic cp /usr/mdec/boot cdrom/boot
+.Dl Ic cp /usr/mdec/bootxx_cd9660 bootxx
+.Dl Ic installboot -o console=com0,speed=19200 -m i386 -e bootxx
+.Dl Ic makefs -t cd9660 -o 'bootimage=i386;bootxx,no-emul-boot' boot.iso \
+       cdrom
+.
+.Pp
+Create a bootable floppy disk with an FFSv1
+file system for a small custom kernel (note: bigger kernels needing
+multiple disks are handled with the ustarfs file system):
+.Dl Ic newfs -s 1440k /dev/rfd0a
+.Bd -ragged -offset indent-two -compact
+.Em Note :
+Ignore the warnings that
+.Xr newfs 8
+displays; it can not write a disklabel,
+which is not a problem for a floppy disk.
+.Ed
+.Dl Ic mount /dev/fd0a /mnt
+.Dl Ic cp /usr/mdec/boot /mnt/boot
+.Dl Ic gzip -9 \*[Lt] sys/arch/i386/compile/mykernel/netbsd \*[Gt] /mnt/netbsd.gz
+.Dl Ic umount /mnt
+.Dl Ic installboot -v /dev/rfd0a /usr/mdec/bootxx_ffsv1
+.
+.Pp
+Create a bootable FAT file system on
+.Sq wd1a ,
+which should have the same offset and size as a FAT primary partition
+in the Master Boot Record (MBR):
+.Dl Ic newfs_msdos -r 16 /dev/rwd1a
+.Bd -ragged -offset indent-two -compact
+.Em Notes :
+The
+.Fl r Ar 16
+is to reserve space for the primary bootstrap.
+.Xr newfs_msdos 8
+will display an
+.Dq MBR type
+such as
+.Ql 1 ,
+.Ql 4 ,
+or
+.Ql 6 ;
+the MBR partition type of the appropriate primary partition should be
+changed to this value.
+.Ed
+.Dl Ic mount -t msdos /dev/wd1a /mnt
+.Dl Ic cp /usr/mdec/boot /mnt/boot
+.Dl Ic cp path/to/kernel /mnt/netbsd
+.Dl Ic umount /mnt
+.Dl Ic installboot -t raw /dev/rwd1a /usr/mdec/bootxx_msdos
+.Pp
+Make the existing FAT16 filesystem on
+.Sq sd0e
+bootable.
+This can be used to make USB memory bootable provided it has 512 byte
+sectors and that the manufacturer correctly initialised the file system.
+.Dl Ic mount -t msdos /dev/sd0e /mnt
+.Dl Ic cp /usr/mdec/boot /mnt/boot
+.Dl Ic cp path/to/kernel /mnt/netbsd
+.Dl Ic umount /mnt
+.Dl Ic installboot /dev/rsd0e /usr/mdec/bootxx_fat16
+It may also be necessary to use
+.Nm fdisk
+to make the device itself bootable.
+.
+.Pp
+Switch the existing installed bootstrap to use a serial console without
+reinstalling or altering other options such as timeout.
+.Dl Ic installboot -e -o console=com0 /dev/rwd0a
+.Ss Nx Ns Tn /macppc
+Note the
+.Nm
+utility is only required for macppc machines with OpenFirmware version 2
+to boot.
+OpenFirmware 3 cannot load bootblocks specified in the Apple partition
+map.
+.Pp
+Install the Berkeley Fast File System primary bootstrap on to disk
+.Sq wd0 :
+.Dl Ic installboot /dev/rwd0c /usr/mdec/bootxx /ofwboot
+.Pp
+The secondary
+.Nx Ns Tn /macppc
+bootstrap is located in
+.Pa /usr/mdec/ofwboot .
+.Pp
+The primary bootstrap requires the raw
+.Pa ofwboot
+for the secondary bootstrap, not
+.Pa ofwboot.xcf ,
+which is used for the OpenFirmware to load kernels.
+.Ss Nx Ns Tn /next68k
+Install the bootstrap on to disk
+.Sq sd0 :
+.Dl Ic installboot /dev/rsd0c /usr/mdec/boot
+.Pp
+.
+.Ss Nx Ns Tn /pmax
+Install the Berkeley Fast File System primary bootstrap on to disk
+.Sq sd0 :
+.Dl Ic installboot /dev/rsd0c /usr/mdec/bootxx_ffs
+.Pp
+.Nx Ns Tn /pmax
+requires that this file system starts at block 0 of the disk.
+.Pp
+Install the ISO 9660 primary bootstrap in the file
+.Pa /tmp/cd-image :
+.Dl Ic installboot -m pmax /tmp/cd-image /usr/mdec/bootxx_cd9660
+.Pp
+Make an ISO 9660 filesystem in the file
+.Pa /tmp/cd-image
+and install the ISO 9660 primary bootstrap in the filesystem, where the
+source directory for the ISO 9660 filesystem contains a kernel, the
+primary bootstrap
+.Pa bootxx_cd9660
+and the secondary bootstrap
+.Pa boot.pmax :
+.Dl Ic mkisofs -o /tmp/cd-image -a -l -v iso-source-dir
+.Dl ...
+.Dl 48 51 iso-source-dir/bootxx_cd9660
+.Dl ...
+.Dl Ic installboot -b `expr 48 \e* 4` /tmp/cd-image /usr/mdec/bootxx_cd9660
+.
+.Ss Nx Ns Tn /sparc
+Install the Berkeley Fast File System primary bootstrap on to disk
+.Sq sd0 ,
+with the secondary bootstrap
+.Sq Pa /boot
+already present:
+.Dl Ic installboot /dev/rsd0c /usr/mdec/bootxx /boot
+.
+.Ss Nx Ns Tn /sparc64
+Install the primary bootstrap on to disk
+.Sq sd0 :
+.Dl Ic installboot /dev/rsd0c /usr/mdec/bootblk
+.Pp
+The secondary
+.Nx Ns Tn /sparc64
+bootstrap is located in
+.Pa /usr/mdec/ofwboot .
+.
+.Ss Nx Ns Tn /sun2 and Nx Ns Tn /sun3
+Install the Berkeley Fast File System primary bootstrap on to disk
+.Sq sd0 ,
+with the secondary bootstrap
+.Sq Pa /boot
+already present:
+.Dl Ic installboot /dev/rsd0c /usr/mdec/bootxx /boot
+.
+.Sh SEE ALSO
+.Xr uname 3 ,
+.Xr boot 8 ,
+.Xr disklabel 8 ,
+.Xr dumpfs 8 ,
+.Xr fdisk 8 ,
+.Xr pxeboot 8
+.
+.Sh HISTORY
+This implementation of
+.Nm
+appeared in
+.Nx 1.6 .
+.
+.Sh AUTHORS
+The machine independent portion of this implementation of
+.Nm
+was written by Luke Mewburn.
+The following people contributed to the various machine dependent
+back-ends:
+Simon Burge (pmax),
+Chris Demetriou (alpha),
+Matthew Fredette (sun2, sun3),
+Matthew Green (sparc64),
+Ross Harvey (alpha),
+Michael Hitch (amiga),
+Paul Kranenburg (sparc),
+David Laight (i386),
+Christian Limpach (next68k),
+Luke Mewburn (macppc),
+Matt Thomas (vax),
+Izumi Tsutsui (news68k, newsmips),
+and
+UCHIYAMA Yasushi (ews4800mips).
+.
+.Sh BUGS
+There are not currently primary bootstraps to support all file systems
+types which are capable of being the root file system.
+.Pp
+If a disk has been converted from
+.Sy FFS
+to
+.Sy RAID
+without the contents of the disk erased, then the original
+.Sy FFS
+installation may be auto-detected instead of the
+.Sy RAID
+installation.
+In this case, the
+.Fl t Ar raid
+option must be provided.
+.
+.Ss Nx Ns Tn /alpha
+The
+.Nx Ns Tn /alpha
+primary bootstrap program can only load the secondary bootstrap program
+from file systems starting at the beginning (block 0) of disks.
+Similarly, the secondary bootstrap program can only load kernels from
+file systems starting at the beginning of disks.
+.Pp
+The size of primary bootstrap programs is restricted to 7.5KB, even
+though some file systems (e.g., ISO 9660) are able to accommodate larger
+ones.
+.
+.Ss Nx Ns Tn /hp300
+The disk must have a boot partition large enough to hold the bootstrap code.
+Currently the primary bootstrap must be a LIF format file.
+.
+.Ss Nx Ns Tn /i386 and Nx Ns Tn /amd64
+The bootstrap must be installed in the
+.Nx
+partition that starts at the beginning of the mbr partition.
+If that is a valid filesystem and contains the
+.Pa /boot
+program then it will be used as the root filesystem, otherwise the
+.Sq a
+partition will be booted.
+.Pp
+The size of primary bootstrap programs is restricted to 8KB, even
+though some file systems (e.g., ISO 9660) are able to accommodate larger
+ones.
+.
+.Ss Nx Ns Tn /macppc
+Due to restrictions in
+.Nm
+and the secondary bootstrap implementation, file systems where kernels exist
+must start at the beginning of disks.
+.Pp
+Currently,
+.Nm
+doesn't recognize an existing Apple partition map on the disk
+and always writes a faked map to make disks bootable.
+.Pp
+The
+.Nx Ns Tn /macppc
+bootstrap program can't load kernels from
+.Sy FFSv2
+partitions.
+.Ss Nx Ns Tn /next68k
+The size of bootstrap programs is restricted to the free space before
+the file system at the beginning of the disk minus 8KB.
+.
+.Ss Nx Ns Tn /pmax
+The
+.Nx Ns Tn /pmax
+secondary bootstrap program can only load kernels from file
+systems starting at the beginning of disks.
+.Pp
+The size of primary bootstrap programs is restricted to 7.5KB, even
+though some file systems (e.g., ISO 9660) are able to accommodate larger
+ones.
+.
+.Ss Nx Ns Tn /sun2 and Nx Ns Tn /sun3
+The
+.Nx Ns Tn /sun2
+and
+.Nx Ns Tn /sun3
+secondary bootstrap program can only load kernels from file
+systems starting at the beginning of disks.
+.
+.Ss Nx Ns Tn /vax
+The
+.Nx Ns Tn /vax
+secondary bootstrap program can only load kernels from file systems
+starting at the beginning of disks.
+.Pp
+The size of primary bootstrap programs is restricted to 7.5KB, even
+though some file systems (e.g., ISO 9660) are able to accommodate larger
+ones.
diff --git a/usr.sbin/installboot/installboot.c b/usr.sbin/installboot/installboot.c
new file mode 100644 (file)
index 0000000..4de3603
--- /dev/null
@@ -0,0 +1,569 @@
+/*     $NetBSD: installboot.c,v 1.36 2011/11/03 20:46:41 martin Exp $  */
+
+/*-
+ * 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: installboot.c,v 1.36 2011/11/03 20:46:41 martin Exp $");
+#endif /* !__lint */
+
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+
+#include <assert.h>
+#include <err.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "installboot.h"
+
+static void    getmachine(ib_params *, const char *, const char *);
+static void    getfstype(ib_params *, const char *, const char *);
+static void    parseoptions(ib_params *, const char *);
+__dead static  void    usage(void);
+static void    options_usage(void);
+static void    machine_usage(void);
+static void    fstype_usage(void);
+
+static ib_params       installboot_params;
+
+#define OFFSET(field)    offsetof(ib_params, field)
+const struct option {
+       const char      *name;          /* Name of option */
+       ib_flags        flag;           /* Corresponding IB_xxx flag */
+       enum {                          /* Type of option value... */
+               OPT_BOOL,               /* no value */
+               OPT_INT,                /* numeric value */
+               OPT_WORD,               /* space/tab/, terminated */
+               OPT_STRING              /* null terminated */
+       }               type;
+       int             offset;         /* of field in ib_params */
+} options[] = {
+       { "alphasum",   IB_ALPHASUM,    OPT_BOOL,       0 },
+       { "append",     IB_APPEND,      OPT_BOOL,       0 },
+       { "command",    IB_COMMAND,     OPT_STRING,     OFFSET(command) },
+       { "console",    IB_CONSOLE,     OPT_WORD,       OFFSET(console) },
+       { "ioaddr",     IB_CONSADDR,    OPT_INT,        OFFSET(consaddr) },
+       { "keymap",     IB_KEYMAP,      OPT_WORD,       OFFSET(keymap) },
+       { "password",   IB_PASSWORD,    OPT_WORD,       OFFSET(password) },
+       { "resetvideo", IB_RESETVIDEO,  OPT_BOOL,       0 },
+       { "speed",      IB_CONSPEED,    OPT_INT,        OFFSET(conspeed) },
+       { "sunsum",     IB_SUNSUM,      OPT_BOOL,       0 },
+       { "timeout",    IB_TIMEOUT,     OPT_INT,        OFFSET(timeout) },
+       { "modules",    IB_MODULES,     OPT_BOOL,       0 },
+       { "bootconf",   IB_BOOTCONF,    OPT_BOOL,       0 },
+       { .name = NULL },
+};
+#undef OFFSET
+#define OPTION(params, type, opt) (*(type *)((char *)(params) + (opt)->offset))
+
+#define DFL_SECSIZE    512     /* Don't use DEV_BSIZE. It's host's value. */
+
+int
+main(int argc, char *argv[])
+{
+       struct utsname  utsname;
+       ib_params       *params;
+       unsigned long   lval;
+       int             ch, rv, mode;
+       char            *p;
+       const char      *op;
+       ib_flags        unsupported_flags;
+
+       setprogname(argv[0]);
+       params = &installboot_params;
+       memset(params, 0, sizeof(*params));
+       params->fsfd = -1;
+       params->s1fd = -1;
+       if ((p = getenv("MACHINE")) != NULL)
+               getmachine(params, p, "$MACHINE");
+
+       while ((ch = getopt(argc, argv, "b:B:cefm:no:t:v")) != -1) {
+               switch (ch) {
+
+               case 'b':
+               case 'B':
+                       if (*optarg == '\0')
+                               goto badblock;
+                       lval = strtoul(optarg, &p, 0);
+                       if (lval > UINT32_MAX || *p != '\0') {
+ badblock:
+                               errx(1, "Invalid block number `%s'", optarg);
+                       }
+                       if (ch == 'b') {
+                               params->s1start = (uint32_t)lval;
+                               params->flags |= IB_STAGE1START;
+                       } else {
+                               params->s2start = (uint32_t)lval;
+                               params->flags |= IB_STAGE2START;
+                       }
+                       break;
+
+               case 'c':
+                       params->flags |= IB_CLEAR;
+                       break;
+
+               case 'e':
+                       params->flags |= IB_EDIT;
+                       break;
+
+               case 'f':
+                       params->flags |= IB_FORCE;
+                       break;
+
+               case 'm':
+                       getmachine(params, optarg, "-m");
+                       break;
+
+               case 'n':
+                       params->flags |= IB_NOWRITE;
+                       break;
+
+               case 'o':
+                       parseoptions(params, optarg);
+                       break;
+
+               case 't':
+                       getfstype(params, optarg, "-t");
+                       break;
+
+               case 'v':
+                       params->flags |= IB_VERBOSE;
+                       break;
+
+               case '?':
+               default:
+                       usage();
+                       /* NOTREACHED */
+
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (params->flags & IB_CLEAR && params->flags & IB_EDIT)
+               usage();
+       if (argc < 1 || argc + 2 * !!(params->flags & (IB_CLEAR | IB_EDIT)) > 3)
+               usage();
+
+       /* set missing defaults */
+       if (params->machine == NULL) {
+               if (uname(&utsname) == -1)
+                       err(1, "Determine uname");
+               getmachine(params, utsname.machine, "uname()");
+       }
+
+       /* Check that options are supported by this system */
+       unsupported_flags = params->flags & ~params->machine->valid_flags;
+       unsupported_flags &= ~(IB_VERBOSE | IB_NOWRITE | IB_CLEAR | IB_EDIT
+                               | IB_FORCE);
+       if (unsupported_flags != 0) {
+               int ndx;
+               for (ndx = 0; options[ndx].name != NULL; ndx++) {
+                       if (unsupported_flags & options[ndx].flag) {
+                               unsupported_flags &= ~options[ndx].flag;
+                               warnx("`-o %s' is not supported for %s",
+                                   options[ndx].name, params->machine->name);
+                       }
+               }
+               if (unsupported_flags & IB_STAGE1START)
+                       warnx("`-b bno' is not supported for %s",
+                           params->machine->name);
+               if (unsupported_flags & IB_STAGE2START)
+                       warnx("`-B bno' is not supported for %s",
+                           params->machine->name);
+               unsupported_flags &= ~(IB_STAGE1START | IB_STAGE2START);
+               if (unsupported_flags != 0)
+                       warnx("Unknown unsupported flag %#x (coding error!)",
+                           unsupported_flags);
+               exit(1);
+       }
+       /* and some illegal combinations */
+       if (params->flags & IB_STAGE1START && params->flags & IB_APPEND) {
+               warnx("Can't use `-b bno' with `-o append'");
+               exit(1);
+       }
+       if (params->flags & IB_CLEAR &&
+           params->flags & (IB_STAGE1START | IB_STAGE2START | IB_APPEND)) {
+               warnx("Can't use `-b bno', `-B bno' or `-o append' with `-c'");
+               exit(1);
+       }
+
+       if (argc >= 3) {
+               params->stage2 = argv[2];
+       }
+
+       params->filesystem = argv[0];
+       if (params->flags & IB_NOWRITE) {
+               op = "only";
+               mode = O_RDONLY;
+       } else {
+               op = "write";
+               mode = O_RDWR;
+       }
+       /* XXX should be specified via option */
+       params->sectorsize = DFL_SECSIZE;
+       if ((params->fsfd = open(params->filesystem, mode, 0600)) == -1)
+               err(1, "Opening file system `%s' read-%s",
+                   params->filesystem, op);
+       if (fstat(params->fsfd, &params->fsstat) == -1)
+               err(1, "Examining file system `%s'", params->filesystem);
+       if (params->fstype != NULL) {
+               if (! params->fstype->match(params))
+                       errx(1, "File system `%s' is not of type %s",
+                           params->filesystem, params->fstype->name);
+       } else {
+               if (params->stage2 != NULL) {
+                       params->fstype = &fstypes[0];
+                       while (params->fstype->name != NULL &&
+                                   !params->fstype->match(params))
+                               params->fstype++;
+                       if (params->fstype->name == NULL)
+                               errx(1, "File system `%s' is of an unknown type",
+                                   params->filesystem);
+               }
+       }
+
+       if (argc >= 2) {
+               if ((params->s1fd = open(argv[1], O_RDONLY, 0600)) == -1)
+                       err(1, "Opening primary bootstrap `%s'", argv[1]);
+               if (fstat(params->s1fd, &params->s1stat) == -1)
+                       err(1, "Examining primary bootstrap `%s'", argv[1]);
+               if (!S_ISREG(params->s1stat.st_mode))
+                       errx(1, "`%s' must be a regular file", argv[1]);
+               params->stage1 = argv[1];
+       }
+       assert(params->machine != NULL);
+
+       if (params->flags & IB_VERBOSE) {
+               printf("File system:         %s\n", params->filesystem);
+               if (params->fstype) 
+                       printf("File system type:    %s (blocksize %u, "
+                               "needswap %d)\n",
+                           params->fstype->name, params->fstype->blocksize,
+                           params->fstype->needswap);
+               if (!(params->flags & IB_EDIT))
+                       printf("Primary bootstrap:   %s\n",
+                           (params->flags & IB_CLEAR) ? "(to be cleared)"
+                           : params->stage1 ? params->stage1 : "(none)" );
+               if (params->stage2 != NULL)
+                       printf("Secondary bootstrap: %s\n", params->stage2);
+       }
+
+       if (params->flags & IB_EDIT) {
+               op = "Edit";
+               rv = params->machine->editboot(params);
+       } else if (params->flags & IB_CLEAR) {
+               op = "Clear";
+               rv = params->machine->clearboot(params);
+       } else {
+               if (argc < 2)
+                       errx(EXIT_FAILURE, "Please specify the primary "
+                           "bootstrap file");
+               op = "Set";
+               rv = params->machine->setboot(params);
+       }
+       if (rv == 0)
+               errx(1, "%s bootstrap operation failed", op);
+
+       if (S_ISREG(params->fsstat.st_mode)) {
+               if (fsync(params->fsfd) == -1)
+                       err(1, "Synchronising file system `%s'",
+                           params->filesystem);
+       } else {
+               /* Sync filesystems (to clean in-memory superblock?) */
+               sync();
+       }
+       if (close(params->fsfd) == -1)
+               err(1, "Closing file system `%s'", params->filesystem);
+       if (argc == 2)
+               if (close(params->s1fd) == -1)
+                       err(1, "Closing primary bootstrap `%s'",
+                           params->stage1);
+
+       exit(0);
+       /* NOTREACHED */
+}
+
+static void
+parseoptions(ib_params *params, const char *option)
+{
+       char *cp;
+       const struct option *opt;
+       int len;
+       unsigned long val;
+
+       assert(params != NULL);
+       assert(option != NULL);
+
+       for (;; option += len) {
+               option += strspn(option, ", \t");
+               if (*option == 0)
+                       return;
+               len = strcspn(option, "=,");
+               for (opt = options; opt->name != NULL; opt++) {
+                       if (memcmp(option, opt->name, len) == 0
+                           && opt->name[len] == 0)
+                               break;
+               }
+               if (opt->name == NULL) {
+                       len = strcspn(option, ",");
+                       warnx("Unknown option `-o %.*s'", len, option);
+                       break;
+               }
+               params->flags |= opt->flag;
+               if (opt->type == OPT_BOOL) {
+                       if (option[len] != '=')
+                               continue;
+                       warnx("Option `%s' must not have a value", opt->name);
+                       break;
+               }
+               if (option[len] != '=') {
+                       warnx("Option `%s' must have a value", opt->name);
+                       break;
+               }
+               option += len + 1;
+               len = strcspn(option, ",");
+               switch (opt->type) {
+               case OPT_STRING:
+                       len = strlen(option);
+                       /* FALLTHROUGH */
+               case OPT_WORD:
+                       cp = strdup(option);
+                       if (cp == NULL)
+                               err(1, "strdup");
+                       cp[len] = 0;
+                       OPTION(params, char *, opt) = cp;
+                       continue;
+               case OPT_INT:
+                       val = strtoul(option, &cp, 0);
+                       if (cp > option + len || (*cp != 0 && *cp != ','))
+                               break;
+                       if (val > INT_MAX)
+                               break;
+                       OPTION(params, int, opt) = (int)val;
+                       continue;
+               default:
+                       errx(1, "Internal error: option `%s' has invalid type %d",
+                               opt->name, opt->type);
+               }
+               warnx("Invalid option value `%s=%.*s'", opt->name, len, option);
+               break;
+       }
+       options_usage();
+       exit(1);
+}
+
+static void
+options_usage(void)
+{
+       int ndx;
+       const char *pfx;
+
+       warnx("Valid options are:");
+       pfx = "\t";
+       for (ndx = 0; options[ndx].name != 0; ndx++) {
+               fprintf(stderr, "%s%s", pfx, options[ndx].name);
+               switch (options[ndx].type) {
+               case OPT_INT:
+                       fprintf(stderr, "=number");
+                       break;
+               case OPT_WORD:
+                       fprintf(stderr, "=word");
+                       break;
+               case OPT_STRING:
+                       fprintf(stderr, "=string");
+                       break;
+               default:
+                       break;
+               }
+               if ((ndx % 5) == 4)
+                       pfx = ",\n\t";
+               else
+                       pfx = ", ";
+       }
+       fprintf(stderr, "\n");
+}
+
+int
+no_setboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+       warnx("%s: bootstrap installation is not supported",
+           params->machine->name);
+       return (0);
+}
+
+int
+no_clearboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+       warnx("%s: bootstrap removal is not supported",
+           params->machine->name);
+       return (0);
+}
+
+int
+no_editboot(ib_params *params)
+{
+
+       assert(params != NULL);
+
+       warnx("%s: bootstrap editing is not supported",
+           params->machine->name);
+       return (0);
+}
+
+
+static void
+getmachine(ib_params *param, const char *mach, const char *provider)
+{
+       int     i;
+
+       assert(param != NULL);
+       assert(mach != NULL);
+       assert(provider != NULL);
+
+       for (i = 0; machines[i] != NULL; i++) {
+               if (machines[i]->name == NULL)
+                       continue;
+               if (strcmp(machines[i]->name, mach) == 0) {
+                       param->machine = machines[i];
+                       return;
+               }
+       }
+       warnx("Invalid machine `%s' from %s", mach, provider);
+       machine_usage();
+       exit(1);
+}
+
+static void
+machine_usage(void)
+{
+       const char *prefix;
+       int     i;
+       int col, len;
+       const char *name;
+       int     wincol=80;
+#ifdef TIOCGWINSZ
+       struct winsize win;
+
+       if (ioctl(fileno(stderr), TIOCGWINSZ, &win) == 0 && win.ws_col > 0)
+               wincol = win.ws_col;
+#endif
+
+       warnx("Supported machines are:");
+       prefix="\t";
+       col = 8 + 3;
+       for (i = 0; machines[i] != NULL; i++) {
+               name = machines[i]->name;
+               if (name == NULL)
+                       continue;
+               len = strlen(name);
+               if (col + len > wincol) {
+                       prefix=",\n\t";
+                       col = -2 + 8 + 3;
+               }
+               col += fprintf(stderr, "%s%s", prefix, name);
+               prefix=", ";
+       }
+       fputs("\n", stderr);
+}
+
+static void
+getfstype(ib_params *param, const char *fstype, const char *provider)
+{
+       int i;
+
+       assert(param != NULL);
+       assert(fstype != NULL);
+       assert(provider != NULL);
+
+       for (i = 0; fstypes[i].name != NULL; i++) {
+               if (strcmp(fstypes[i].name, fstype) == 0) {
+                       param->fstype = &fstypes[i];
+                       return;
+               }
+       }
+       warnx("Invalid file system type `%s' from %s", fstype, provider);
+       fstype_usage();
+       exit(1);
+}
+
+static void
+fstype_usage(void)
+{
+#ifndef NO_STAGE2
+       const char *prefix;
+       int     i;
+
+       warnx("Supported file system types are:");
+#define FSTYPES_PER_LINE       9
+       prefix="\t";
+       for (i = 0; fstypes[i].name != NULL; i++) {
+               if (i && (i % FSTYPES_PER_LINE) == 0)
+                       prefix=",\n\t";
+               fprintf(stderr, "%s%s", prefix, fstypes[i].name);
+               prefix=", ";
+       }
+       fputs("\n", stderr);
+#endif
+}
+
+static void
+usage(void)
+{
+       const char      *prog;
+
+       prog = getprogname();
+       fprintf(stderr,
+"usage: %s [-fnv] [-B s2bno] [-b s1bno] [-m machine] [-o options]\n"
+"\t\t   [-t fstype] filesystem primary [secondary]\n"
+"usage: %s -c [-fnv] [-m machine] [-o options] [-t fstype] filesystem\n"
+"usage: %s -e [-fnv] [-m machine] [-o options] bootstrap\n",
+           prog, prog, prog);
+       machine_usage();
+       fstype_usage();
+       options_usage();
+       exit(1);
+}
diff --git a/usr.sbin/installboot/installboot.h b/usr.sbin/installboot/installboot.h
new file mode 100644 (file)
index 0000000..00cb0c9
--- /dev/null
@@ -0,0 +1,185 @@
+/*     $NetBSD: installboot.h,v 1.38 2011/06/14 05:35:08 matt Exp $    */
+
+/*-
+ * 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.
+ *
+ * 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 */
+       IB_EDIT =       1<<3,           /* edit boot parameters */
+       IB_FORCE =      1<<4,           /* Ignore some consistency checks */
+
+                               /* 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_MODULES =    1<<21,          /* i386: load modules */
+       IB_BOOTCONF =   1<<22,          /* i386: read boot.conf */
+} 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 */
+       uint32_t         sectorsize;    /* sector size of target fs */
+               /* 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 *);
+       int             (*editboot)     (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 */
+       off_t           offset;         /* file system offset (e.g. RAID) */
+};
+
+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;
+};
+
+extern struct ib_mach  * const machines[];
+extern struct ib_fs    fstypes[];
+
+       /* installboot.c */
+uint16_t       compute_sunsum(const uint16_t *);
+int            set_sunsum(ib_params *, uint16_t *, uint16_t);
+int            no_setboot(ib_params *);
+int            no_clearboot(ib_params *);
+int            no_editboot(ib_params *);
+
+       /* bbinfo.c */
+int            shared_bbinfo_clearboot(ib_params *, struct bbinfo_params *,
+                   int (*)(ib_params *, struct bbinfo_params *, uint8_t *));
+int            shared_bbinfo_setboot(ib_params *, struct bbinfo_params *,
+                   int (*)(ib_params *, struct bbinfo_params *, uint8_t *));
+
+       /* fstypes.c */
+int            hardcode_stage2(ib_params *, uint32_t *, ib_block *);
+int            ffs_match(ib_params *);
+int            ffs_findstage2(ib_params *, uint32_t *, ib_block *);
+int            raid_match(ib_params *);
+int            raw_match(ib_params *);
+int            raw_findstage2(ib_params *, uint32_t *, ib_block *);
+int            ext2fs_match(ib_params *);
+int            ext2fs_findstage2(ib_params *, uint32_t *, ib_block *);
+
+       /* machines.c */
+extern struct ib_mach ib_mach_alpha;
+extern struct ib_mach ib_mach_amd64;
+extern struct ib_mach ib_mach_amiga;
+extern struct ib_mach ib_mach_ews4800mips;
+extern struct ib_mach ib_mach_hp300;
+extern struct ib_mach ib_mach_hp700;
+extern struct ib_mach ib_mach_i386;
+extern struct ib_mach ib_mach_landisk;
+extern struct ib_mach ib_mach_macppc;
+extern struct ib_mach ib_mach_news68k;
+extern struct ib_mach ib_mach_newsmips;
+extern struct ib_mach ib_mach_next68k;
+extern struct ib_mach ib_mach_pmax;
+extern struct ib_mach ib_mach_sparc;
+extern struct ib_mach ib_mach_sparc64;
+extern struct ib_mach ib_mach_sun2;
+extern struct ib_mach ib_mach_sun3;
+extern struct ib_mach ib_mach_vax;
+extern struct ib_mach ib_mach_x68k;
+
+#endif /* _INSTALLBOOT_H */
diff --git a/usr.sbin/installboot/machines.c b/usr.sbin/installboot/machines.c
new file mode 100644 (file)
index 0000000..9320b0a
--- /dev/null
@@ -0,0 +1,97 @@
+/*     $NetBSD: machines.c,v 1.38 2011/06/14 05:35:08 matt Exp $       */
+
+/*-
+ * Copyright (c) 2002-2005 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.
+ *
+ * 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: machines.c,v 1.38 2011/06/14 05:35:08 matt Exp $");
+#endif /* !__lint */
+
+#include <sys/types.h>
+#include "installboot.h"
+
+/*
+ * Define these here so they end up as zero-filled bss if installboot
+ * isn't built with all the architectures defined.
+ * A lot simpler that conditionally including the definitions themselves.
+ */
+struct ib_mach
+    ib_mach_alpha,
+    ib_mach_amd64,
+    ib_mach_amiga,
+    ib_mach_emips,
+    ib_mach_ews4800mips,
+    ib_mach_hp300,
+    ib_mach_hp700,
+    ib_mach_i386,
+    ib_mach_landisk,
+    ib_mach_macppc,
+    ib_mach_news68k,
+    ib_mach_newsmips,
+    ib_mach_next68k,
+    ib_mach_pmax,
+    ib_mach_sparc,
+    ib_mach_sparc64,
+    ib_mach_sun2,
+    ib_mach_sun3,
+    ib_mach_vax,
+    ib_mach_x68k;
+
+struct ib_mach * const machines[] = {
+    &ib_mach_alpha,
+    &ib_mach_amd64,
+    &ib_mach_amiga,
+    &ib_mach_emips,
+    &ib_mach_ews4800mips,
+    &ib_mach_hp300,
+    &ib_mach_hp700,
+    &ib_mach_i386,
+    &ib_mach_landisk,
+    &ib_mach_macppc,
+    &ib_mach_news68k,
+    &ib_mach_newsmips,
+    &ib_mach_next68k,
+    &ib_mach_pmax,
+    &ib_mach_sparc,
+    &ib_mach_sparc64,
+    &ib_mach_sun2,
+    &ib_mach_sun3,
+    &ib_mach_vax,
+    &ib_mach_x68k,
+    NULL
+};
+
+#if 0
+       { "shark",      no_setboot,     no_clearboot,   no_editboot, 0 },
+#endif
diff --git a/usr.sbin/installboot/sum.c b/usr.sbin/installboot/sum.c
new file mode 100644 (file)
index 0000000..87c7f49
--- /dev/null
@@ -0,0 +1,108 @@
+/*     $NetBSD: sum.c,v 1.5 2010/01/14 16:27:49 tsutsui Exp $  */
+
+/*-
+ * 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.
+ *
+ * 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) 1999 Ross Harvey.  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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Ross Harvey
+ *     for the NetBSD Project.
+ * 4. 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(__lint)
+__RCSID("$NetBSD: sum.c,v 1.5 2010/01/14 16:27:49 tsutsui Exp $");
+#endif /* !__lint */
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "installboot.h"
+
+
+uint16_t
+compute_sunsum(const uint16_t *bb16)
+{
+       uint16_t        i, s;
+
+       assert(bb16 != NULL);
+
+       s = 0;
+       for (i = 0; i < 255; ++i)
+               s ^= bb16[i];
+       return (s);
+}
+
+int
+set_sunsum(ib_params *params, uint16_t *bb16, uint16_t sum)
+{
+
+       assert(params != NULL);
+       assert(bb16 != NULL);
+
+#define        SUNSUM_OFFSET   255
+       if (params->flags & IB_VERBOSE) {
+               printf("Old Sun checksum:          0x%04x\n",
+                   be16toh(bb16[SUNSUM_OFFSET]));
+               printf("Recalculated Sun checksum: 0x%04x\n", be16toh(sum));
+       }
+               // XXX: does this need to be big endian?
+       bb16[SUNSUM_OFFSET] = sum;
+       return (1);
+}