Home | History | Annotate | Line # | Download | only in installboot
installboot.c revision 1.28.4.1
      1 /*	$NetBSD: installboot.c,v 1.28.4.1 2015/03/29 07:42:53 snj Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1995 Waldi Ravens
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *        This product includes software developed by Waldi Ravens.
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/types.h>
     34 #include <sys/param.h>
     35 #include <sys/sysctl.h>
     36 #include <sys/ioctl.h>
     37 #include <unistd.h>
     38 #include <string.h>
     39 #include <stdlib.h>
     40 #include <stdio.h>
     41 #include <paths.h>
     42 #include <fcntl.h>
     43 #include <errno.h>
     44 #include <err.h>
     45 #include <limits.h>
     46 #include <nlist.h>
     47 #include <kvm.h>
     48 
     49 #define	DKTYPENAMES
     50 #define	FSTYPENAMES
     51 #include <sys/disklabel.h>
     52 #include <machine/ahdilabel.h>
     53 
     54 #include "installboot.h"
     55 
     56 static void	usage(void);
     57 #ifdef CHECK_OS_BOOTVERSION
     58 static void	oscheck(void);
     59 #endif
     60 static u_int	abcksum(void *);
     61 static void	setNVpref(void);
     62 static void	setIDEpar(u_int8_t *, size_t);
     63 static void	mkahdiboot(struct ahdi_root *, char *,
     64 						char *, u_int32_t);
     65 static void	mkbootblock(struct bootblock *, char *,
     66 				char *, struct disklabel *, u_int);
     67 static void	install_fd(char *, struct disklabel *);
     68 static void	install_sd(char *, struct disklabel *);
     69 static void	install_wd(char *, struct disklabel *);
     70 
     71 static struct bootblock	bootarea;
     72 static struct ahdi_root ahdiboot;
     73 static const char	mdecpath[] = PATH_MDEC;
     74 static const char	stdpath[] = PATH_STD;
     75 static const char	milanpath[] = PATH_MILAN;
     76 static int		nowrite = 0;
     77 static int		verbose = 0;
     78 static int		trackpercyl = 0;
     79 static int		secpertrack = 0;
     80 static int		milan = 0;
     81 
     82 static void
     83 usage(void)
     84 {
     85 	fprintf(stderr,
     86 		"usage: installboot [options] device\n"
     87 		"where options are:\n"
     88 		"\t-N  do not actually write anything on the disk\n"
     89 		"\t-m  use Milan boot blocks\n"
     90 		"\t-t  number of tracks per cylinder (IDE disk)\n"
     91 		"\t-u  number of sectors per track (IDE disk)\n"
     92 		"\t-v  verbose mode\n");
     93 	exit(EXIT_FAILURE);
     94 }
     95 
     96 int
     97 main(int argc, char *argv[])
     98 {
     99 	struct disklabel dl;
    100 	char		 *dn;
    101 	char		 *devchr;
    102 	int		 fd, c;
    103 
    104 #ifdef CHECK_OS_BOOTVERSION
    105 	/* check OS bootversion */
    106 	oscheck();
    107 #endif
    108 
    109 	/* parse options */
    110 	while ((c = getopt(argc, argv, "Nmt:u:v")) != -1) {
    111 		switch (c) {
    112 		  case 'N':
    113 			nowrite = 1;
    114 			break;
    115 		  case 'm':
    116 			milan = 1;
    117 			break;
    118 		  case 't':
    119 			trackpercyl = atoi(optarg);
    120 			break;
    121 		  case 'u':
    122 			secpertrack = atoi(optarg);
    123 			break;
    124 		  case 'v':
    125 			verbose = 1;
    126 			break;
    127 		  default:
    128 			usage();
    129 		}
    130 	}
    131 	argv += optind;
    132 	argc -= optind;
    133 	if (argc != 1)
    134 		usage();
    135 
    136 	/* get disk label */
    137 	size_t dnlen = sizeof(_PATH_DEV) + strlen(argv[0]) + 8;
    138 	dn = alloca(dnlen);
    139 	if (!strchr(argv[0], '/')) {
    140 		snprintf(dn, dnlen, "%sr%s%c", _PATH_DEV, argv[0],
    141 		    RAW_PART + 'a');
    142 		fd = open(dn, O_RDONLY);
    143 		if (fd < 0 && errno == ENOENT) {
    144 			snprintf(dn, dnlen, "%sr%s", _PATH_DEV, argv[0]);
    145 			fd = open(dn, O_RDONLY);
    146 		}
    147 	} else {
    148 		snprintf(dn, dnlen, "%s", argv[0]);
    149 		fd = open(dn, O_RDONLY);
    150 	}
    151 	if (fd < 0)
    152 		err(EXIT_FAILURE, "%s", dn);
    153 	if (ioctl(fd, DIOCGDINFO, &dl))
    154 		err(EXIT_FAILURE, "%s: DIOCGDINFO", dn);
    155 	if (close(fd))
    156 		err(EXIT_FAILURE, "%s", dn);
    157 
    158 	/* Eg: in /dev/fd0c, set devchr to point to the 'f' */
    159 	devchr = strrchr(dn, '/') + 1;
    160 	if (*devchr == 'r')
    161 		++devchr;
    162 
    163 	switch (*devchr) {
    164 		case 'f': /* fd */
    165 			install_fd(dn, &dl);
    166 			break;
    167 		case 'w': /* wd */
    168 			install_wd(dn, &dl);
    169 			setNVpref();
    170 			break;
    171 		case 's': /* sd */
    172 			install_sd(dn, &dl);
    173 			setNVpref();
    174 			break;
    175 		default:
    176 			errx(EXIT_FAILURE,
    177 			     "%s: '%c': Device type not supported.",
    178 			     dn, *devchr);
    179 	}
    180 
    181 	return(EXIT_SUCCESS);
    182 }
    183 
    184 #ifdef CHECK_OS_BOOTVERSION
    185 static void
    186 oscheck(void)
    187 {
    188 	struct nlist kbv[] = {
    189 		{ .n_name = "_bootversion" },
    190 		{ .n_name = NULL }
    191 	};
    192 	kvm_t		*kd_kern;
    193 	char		errbuf[_POSIX2_LINE_MAX];
    194 	u_short		kvers;
    195 	struct stat	sb;
    196 
    197 	if (stat(_PATH_UNIX, &sb) < 0) {
    198 		warnx("Cannot stat %s, no bootversion check done", _PATH_UNIX);
    199 		return;
    200 	}
    201 
    202 	kd_kern = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
    203 	if (kd_kern == NULL)
    204 		errx(EXIT_FAILURE, "kvm_openfiles: %s", errbuf);
    205 	if (kvm_nlist(kd_kern, kbv) == -1)
    206 		errx(EXIT_FAILURE, "kvm_nlist: %s", kvm_geterr(kd_kern));
    207 	if (kbv[0].n_value == 0)
    208 		errx(EXIT_FAILURE, "%s not in namelist", kbv[0].n_name);
    209 	if (kvm_read(kd_kern, kbv[0].n_value, &kvers, sizeof(kvers)) == -1)
    210 		errx(EXIT_FAILURE, "kvm_read: %s", kvm_geterr(kd_kern));
    211 	kvm_close(kd_kern);
    212 	if (kvers != BOOTVERSION)
    213 		errx(EXIT_FAILURE, "Kern bootversion: %d, expected: %d",
    214 		    kvers, BOOTVERSION);
    215 }
    216 #endif
    217 
    218 static void
    219 install_fd(char *devnm, struct disklabel *label)
    220 {
    221 	const char	 *machpath;
    222 	char		 *xxboot, *bootxx;
    223 	struct partition *rootpart;
    224 
    225 	if (label->d_secsize != 512)
    226 		errx(EXIT_FAILURE,
    227 		     "%s: %u: Block size not supported.", devnm,
    228 							  label->d_secsize);
    229 	if (label->d_ntracks != 2)
    230 		errx(EXIT_FAILURE,
    231 		     "%s: Single sided floppy not supported.", devnm);
    232 
    233 	if (milan)
    234 		machpath = milanpath;
    235 	else
    236 		machpath = stdpath;
    237 	size_t xxbootlen = strlen(mdecpath) + strlen(machpath) + 8;
    238 	xxboot = alloca(xxbootlen);
    239 	snprintf(xxboot, xxbootlen, "%s%sfdboot", mdecpath, machpath);
    240 	bootxx = alloca(xxbootlen);
    241 	snprintf(bootxx, xxbootlen, "%s%sbootxx", mdecpath, machpath);
    242 
    243 	/* first used partition (a, b or c) */		/* XXX */
    244 	for (rootpart = label->d_partitions; ; ++rootpart) {
    245 		if (rootpart->p_size)
    246 			break;
    247 	}
    248 	if (rootpart != label->d_partitions) {		/* XXX */
    249 		*(label->d_partitions) = *rootpart;
    250 		memset(rootpart, 0, sizeof(*rootpart));
    251 	}
    252 	label->d_partitions->p_fstype = FS_BSDFFS;	/* XXX */
    253 	label->d_npartitions = 1;
    254 	label->d_checksum = 0;
    255 	label->d_checksum = dkcksum(label);
    256 
    257 	trackpercyl = secpertrack = 0;
    258 	mkbootblock(&bootarea, xxboot, bootxx, label, 0);
    259 
    260 	if (!nowrite) {
    261 		int	fd;
    262 		if ((fd = open(devnm, O_WRONLY)) < 0)
    263 			err(EXIT_FAILURE, "%s", devnm);
    264 		if (write(fd, &bootarea, sizeof(bootarea)) != sizeof(bootarea))
    265 			err(EXIT_FAILURE, "%s", devnm);
    266 		if (close(fd))
    267 			err(EXIT_FAILURE, "%s", devnm);
    268 		if (verbose)
    269 			printf("Boot block installed on %s\n", devnm);
    270 	}
    271 }
    272 
    273 static void
    274 install_sd(char *devnm, struct disklabel *label)
    275 {
    276 	const char	 *machpath;
    277 	char		 *xxb00t, *xxboot, *bootxx;
    278 	struct disklabel rawlabel;
    279 	u_int32_t	 bbsec;
    280 	u_int		 magic;
    281 
    282 	if (label->d_partitions[0].p_size == 0)
    283 		errx(EXIT_FAILURE, "%s: No root-filesystem.", devnm);
    284 	if (label->d_partitions[0].p_fstype != FS_BSDFFS)
    285 		errx(EXIT_FAILURE, "%s: %s: Illegal root-filesystem type.",
    286 		     devnm, fstypenames[label->d_partitions[0].p_fstype]);
    287 
    288 	bbsec = readdisklabel(devnm, &rawlabel);
    289 	if (bbsec == NO_BOOT_BLOCK)
    290 		errx(EXIT_FAILURE, "%s: No NetBSD boot block.", devnm);
    291 	if (memcmp(label, &rawlabel, sizeof(*label)))
    292 		errx(EXIT_FAILURE, "%s: Invalid NetBSD boot block.", devnm);
    293 
    294 	if (milan)
    295 		machpath = milanpath;
    296 	else
    297 		machpath = stdpath;
    298 	if (bbsec) {
    299 		size_t xxb00tlen = strlen(mdecpath) + strlen(machpath) + 14;
    300 		xxb00t = alloca(xxb00tlen);
    301 		snprintf(xxb00t, xxb00tlen, "%s%ssdb00t.ahdi", mdecpath, machpath);
    302 		xxboot = alloca(xxb00tlen);
    303 		snprintf(xxboot, xxb00tlen, "%s%sxxboot.ahdi", mdecpath, machpath);
    304 		magic = AHDIMAGIC;
    305 	} else {
    306 		size_t xxbootlen = strlen(mdecpath) + strlen(machpath) + 8;
    307 		xxb00t = NULL;
    308 		xxboot = alloca(xxbootlen);
    309 		snprintf(xxboot, xxbootlen, "%s%ssdboot", mdecpath, machpath);
    310 		magic = NBDAMAGIC;
    311 	}
    312 	size_t bootxxlen = strlen(mdecpath) + strlen(machpath) + 8;
    313 	bootxx = alloca(bootxxlen);
    314 	snprintf(bootxx, bootxxlen, "%s%sbootxx", mdecpath, machpath);
    315 
    316 	trackpercyl = secpertrack = 0;
    317 	if (xxb00t)
    318 		mkahdiboot(&ahdiboot, xxb00t, devnm, bbsec);
    319 	mkbootblock(&bootarea, xxboot, bootxx, label, magic);
    320 
    321 	if (!nowrite) {
    322 		off_t	bbo = (off_t)bbsec * AHDI_BSIZE;
    323 		int	fd;
    324 
    325 		if ((fd = open(devnm, O_WRONLY)) < 0)
    326 			err(EXIT_FAILURE, "%s", devnm);
    327 		if (lseek(fd, bbo, SEEK_SET) != bbo)
    328 			err(EXIT_FAILURE, "%s", devnm);
    329 		if (write(fd, &bootarea, sizeof(bootarea)) != sizeof(bootarea))
    330 			err(EXIT_FAILURE, "%s", devnm);
    331 		if (verbose)
    332 			printf("Boot block installed on %s (sector %d)\n",
    333 			    devnm, bbsec);
    334 		if (xxb00t) {
    335 			if (lseek(fd, (off_t)0, SEEK_SET) != 0)
    336 				err(EXIT_FAILURE, "%s", devnm);
    337 			if (write(fd, &ahdiboot, sizeof(ahdiboot)) !=
    338 			    sizeof(ahdiboot))
    339 				err(EXIT_FAILURE, "%s", devnm);
    340 			if (verbose)
    341 				printf("AHDI root  installed on %s (0)\n",
    342 				    devnm);
    343 		}
    344 		if (close(fd))
    345 			err(EXIT_FAILURE, "%s", devnm);
    346 	}
    347 }
    348 
    349 static void
    350 install_wd(char *devnm, struct disklabel *label)
    351 {
    352 	const char	 *machpath;
    353 	char		 *xxb00t, *xxboot, *bootxx;
    354 	struct disklabel rawlabel;
    355 	u_int32_t	 bbsec;
    356 	u_int		 magic;
    357 
    358 	if (label->d_partitions[0].p_size == 0)
    359 		errx(EXIT_FAILURE, "%s: No root-filesystem.", devnm);
    360 	if (label->d_partitions[0].p_fstype != FS_BSDFFS)
    361 		errx(EXIT_FAILURE, "%s: %s: Illegal root-filesystem type.",
    362 		     devnm, fstypenames[label->d_partitions[0].p_fstype]);
    363 
    364 	bbsec = readdisklabel(devnm, &rawlabel);
    365 	if (bbsec == NO_BOOT_BLOCK)
    366 		errx(EXIT_FAILURE, "%s: No NetBSD boot block.", devnm);
    367 	if (memcmp(label, &rawlabel, sizeof(*label)))
    368 		errx(EXIT_FAILURE, "%s: Invalid NetBSD boot block.", devnm);
    369 
    370 	if (milan)
    371 		machpath = milanpath;
    372 	else
    373 		machpath = stdpath;
    374 	if (bbsec) {
    375 		size_t xxb00tlen = strlen(mdecpath) + strlen(machpath) + 14;
    376 		xxb00t = alloca(xxb00tlen);
    377 		snprintf(xxb00t, xxb00tlen, "%s%swdb00t.ahdi", mdecpath, machpath);
    378 		xxboot = alloca(xxb00tlen);
    379 		snprintf(xxboot, xxb00tlen, "%s%sxxboot.ahdi", mdecpath, machpath);
    380 		magic = AHDIMAGIC;
    381 	} else {
    382 		size_t xxbootlen = strlen(mdecpath) + strlen(machpath) + 8;
    383 		xxb00t = NULL;
    384 		xxboot = alloca(xxbootlen);
    385 		snprintf(xxboot, xxbootlen, "%s%swdboot", mdecpath, machpath);
    386 		magic = NBDAMAGIC;
    387 	}
    388 	size_t bootxxlen = strlen(mdecpath) + strlen(machpath) + 8;
    389 	bootxx = alloca(bootxxlen);
    390 	snprintf(bootxx, bootxxlen, "%s%sbootxx", mdecpath, machpath);
    391 
    392 	if (xxb00t)
    393 		mkahdiboot(&ahdiboot, xxb00t, devnm, bbsec);
    394 	mkbootblock(&bootarea, xxboot, bootxx, label, magic);
    395 
    396 	if (!nowrite) {
    397 		int	fd;
    398 		off_t	bbo;
    399 
    400 		bbo = (off_t)bbsec * AHDI_BSIZE;
    401 		if ((fd = open(devnm, O_WRONLY)) < 0)
    402 			err(EXIT_FAILURE, "%s", devnm);
    403 		if (lseek(fd, bbo, SEEK_SET) != bbo)
    404 			err(EXIT_FAILURE, "%s", devnm);
    405 		if (write(fd, &bootarea, sizeof(bootarea)) != sizeof(bootarea))
    406 			err(EXIT_FAILURE, "%s", devnm);
    407 		if (verbose)
    408 			printf("Boot block installed on %s (sector %d)\n",
    409 			    devnm, bbsec);
    410 		if (xxb00t) {
    411 			if (lseek(fd, (off_t)0, SEEK_SET) != 0)
    412 				err(EXIT_FAILURE, "%s", devnm);
    413 			if (write(fd, &ahdiboot, sizeof(ahdiboot))
    414 							!= sizeof(ahdiboot))
    415 				err(EXIT_FAILURE, "%s", devnm);
    416 			if (verbose)
    417 				printf("AHDI root installed on %s (sector 0)\n",
    418 				    devnm);
    419 		}
    420 		if (close(fd))
    421 			err(EXIT_FAILURE, "%s", devnm);
    422 	}
    423 }
    424 
    425 static void
    426 mkahdiboot(struct ahdi_root *newroot, char *xxb00t, char *devnm,
    427     u_int32_t bbsec)
    428 {
    429 	struct ahdi_root tmproot;
    430 	struct ahdi_part *pd;
    431 	int		 fd;
    432 
    433 	/* read prototype root-sector */
    434 	if ((fd = open(xxb00t, O_RDONLY)) < 0)
    435 		err(EXIT_FAILURE, "%s", xxb00t);
    436 	if (read(fd, &tmproot, sizeof(tmproot)) != sizeof(tmproot))
    437 		err(EXIT_FAILURE, "%s", xxb00t);
    438 	if (close(fd))
    439 		err(EXIT_FAILURE, "%s", xxb00t);
    440 
    441 	/* set tracks/cylinder and sectors/track */
    442 	setIDEpar(tmproot.ar_fill, sizeof(tmproot.ar_fill));
    443 
    444 	/* read current root-sector */
    445 	if ((fd = open(devnm, O_RDONLY)) < 0)
    446 		err(EXIT_FAILURE, "%s", devnm);
    447 	if (read(fd, newroot, sizeof(*newroot)) != sizeof(*newroot))
    448 		err(EXIT_FAILURE, "%s", devnm);
    449 	if (close(fd))
    450 		err(EXIT_FAILURE, "%s", devnm);
    451 
    452 	/* set bootflags */
    453 	for (pd = newroot->ar_parts; pd-newroot->ar_parts < AHDI_MAXRPD; ++pd) {
    454 		if (pd->ap_st == bbsec) {
    455 			pd->ap_flg = 0x21;	/* bootable, pref = NetBSD */
    456 			goto gotit;
    457 		}
    458 	}
    459 	errx(EXIT_FAILURE,
    460 	     "%s: NetBSD boot block not on primary AHDI partition.", devnm);
    461 
    462 gotit:	/* copy code from prototype and set new checksum */
    463 	memcpy(newroot->ar_fill, tmproot.ar_fill, sizeof(tmproot.ar_fill));
    464 	newroot->ar_checksum = 0;
    465 	newroot->ar_checksum = 0x1234 - abcksum(newroot);
    466 
    467 	if (verbose)
    468 		printf("AHDI      boot loader: %s\n", xxb00t);
    469 }
    470 
    471 static void
    472 mkbootblock(struct bootblock *bb, char *xxb, char *bxx,
    473     struct disklabel *label, u_int magic)
    474 {
    475 	int		 fd;
    476 
    477 	memset(bb, 0, sizeof(*bb));
    478 
    479 	/* set boot block magic */
    480 	bb->bb_magic = magic;
    481 
    482 	/* set disk pack label */
    483 	BBSETLABEL(bb, label);
    484 
    485 	/* set second-stage boot loader */
    486 	if ((fd = open(bxx, O_RDONLY)) < 0)
    487 		err(EXIT_FAILURE, "%s", bxx);
    488 	if (read(fd, bb->bb_bootxx, sizeof(bb->bb_bootxx))
    489 					!= sizeof(bb->bb_bootxx))
    490 		err(EXIT_FAILURE, "%s", bxx);
    491 	if (close(fd))
    492 		err(EXIT_FAILURE, "%s", bxx);
    493 
    494 	/* set first-stage bootloader */
    495 	if ((fd = open(xxb, O_RDONLY)) < 0)
    496 		err(EXIT_FAILURE, "%s", xxb);
    497 	if (read(fd, bb->bb_xxboot, sizeof(bb->bb_xxboot))
    498 					!= sizeof(bb->bb_xxboot))
    499 		err(EXIT_FAILURE, "%s", xxb);
    500 	if (close(fd))
    501 		err(EXIT_FAILURE, "%s", xxb);
    502 
    503 	/* set tracks/cylinder and sectors/track */
    504 	setIDEpar(bb->bb_xxboot, sizeof(bb->bb_xxboot));
    505 
    506 	/* set AHDI checksum */
    507 	*((u_int16_t *)bb->bb_xxboot + 255) = 0;
    508 	*((u_int16_t *)bb->bb_xxboot + 255) = 0x1234 - abcksum(bb->bb_xxboot);
    509 
    510 	if (verbose) {
    511 		printf("Primary   boot loader: %s\n", xxb);
    512 		printf("Secondary boot loader: %s\n", bxx);
    513 	}
    514 }
    515 
    516 static void
    517 setIDEpar (u_int8_t *start, size_t size)
    518 {
    519 	static const u_int8_t	mark[] = { 'N', 'e', 't', 'B', 'S', 'D' };
    520 
    521 	if ((u_int)trackpercyl > 255)
    522 		errx(EXIT_FAILURE,
    523 		     "%d: Illegal tracks/cylinder value (1..255)", trackpercyl);
    524 	if ((u_int)secpertrack > 255)
    525 		errx(EXIT_FAILURE,
    526 		     "%d: Illegal sectors/track value (1..255)", secpertrack);
    527 
    528 	if (trackpercyl || secpertrack) {
    529 		u_int8_t *p;
    530 
    531 		if (!trackpercyl)
    532 			errx(EXIT_FAILURE, "Need tracks/cylinder too.");
    533 		if (!secpertrack)
    534 			errx(EXIT_FAILURE, "Need sectors/track too.");
    535 
    536 		start += 2;
    537 		size  -= sizeof(mark) + 2;
    538 		for (p = start + size; p >= start; --p) {
    539 			if (*p != *mark)
    540 				continue;
    541 			if (!memcmp(p, mark, sizeof(mark)))
    542 				break;
    543 		}
    544 		if (p < start)
    545 			errx(EXIT_FAILURE,
    546 			     "Malformatted xxboot prototype.");
    547 
    548 		*--p = secpertrack;
    549 		*--p = trackpercyl;
    550 
    551 		if (verbose) {
    552 			printf("sectors/track  : %d\n", secpertrack);
    553 			printf("tracks/cylinder: %d\n", trackpercyl);
    554 		}
    555 	}
    556 }
    557 
    558 static void
    559 setNVpref(void)
    560 {
    561 	static const u_char	bootpref = BOOTPREF_NETBSD;
    562 	static const char	nvrdev[] = PATH_NVRAM;
    563 
    564 	if (!nowrite) {
    565 		int	fd;
    566 
    567 		if ((fd = open(nvrdev, O_RDWR)) < 0)
    568 			err(EXIT_FAILURE, "%s", nvrdev);
    569 		if (lseek(fd, (off_t)1, SEEK_SET) != 1)
    570 			err(EXIT_FAILURE, "%s", nvrdev);
    571 		if (write(fd, &bootpref, (size_t)1) != 1)
    572 			err(EXIT_FAILURE, "%s", nvrdev);
    573 		if (close(fd))
    574 			err(EXIT_FAILURE, "%s", nvrdev);
    575 		if (verbose)
    576 			printf("Boot preference set to NetBSD.\n");
    577 	}
    578 }
    579 
    580 static u_int
    581 abcksum (void *bs)
    582 {
    583 	u_int16_t sum  = 0,
    584 		  *st  = (u_int16_t *)bs,
    585 		  *end = (u_int16_t *)bs + 256;
    586 
    587 	while (st < end)
    588 		sum += *st++;
    589 	return(sum);
    590 }
    591