Home | History | Annotate | Line # | Download | only in installboot
installboot.c revision 1.34.2.1
      1 /*	$NetBSD: installboot.c,v 1.34.2.1 2015/09/22 12:05:38 skrll 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 bool		nowrite;
     77 static bool		verbose;
     78 static int		trackpercyl;
     79 static int		secpertrack;
     80 static bool		milan;
     81 
     82 static void
     83 usage(void)
     84 {
     85 	fprintf(stderr,
     86 		"usage: installboot [options] device\n"
     87 #ifndef NO_USAGE
     88 		"where options are:\n"
     89 		"\t-N  do not actually write anything on the disk\n"
     90 		"\t-m  use Milan boot blocks\n"
     91 		"\t-t  number of tracks per cylinder (IDE disk)\n"
     92 		"\t-u  number of sectors per track (IDE disk)\n"
     93 		"\t-v  verbose mode\n"
     94 #endif
     95 		);
     96 	exit(EXIT_FAILURE);
     97 }
     98 
     99 int
    100 main(int argc, char *argv[])
    101 {
    102 	struct disklabel dl;
    103 	char		 *dn;
    104 	char		 *devchr;
    105 	int		 fd, c;
    106 
    107 #ifdef CHECK_OS_BOOTVERSION
    108 	/* check OS bootversion */
    109 	oscheck();
    110 #endif
    111 
    112 	/* parse options */
    113 	while ((c = getopt(argc, argv, "Nmt:u:v")) != -1) {
    114 		switch (c) {
    115 		  case 'N':
    116 			nowrite = true;
    117 			break;
    118 		  case 'm':
    119 			milan = true;
    120 			break;
    121 		  case 't':
    122 			trackpercyl = atoi(optarg);
    123 			break;
    124 		  case 'u':
    125 			secpertrack = atoi(optarg);
    126 			break;
    127 		  case 'v':
    128 			verbose = true;
    129 			break;
    130 		  default:
    131 			usage();
    132 		}
    133 	}
    134 	argv += optind;
    135 	argc -= optind;
    136 	if (argc != 1)
    137 		usage();
    138 
    139 	/* get disk label */
    140 	size_t dnlen = sizeof(_PATH_DEV) + strlen(argv[0]) + 8;
    141 	dn = alloca(dnlen);
    142 	if (!strchr(argv[0], '/')) {
    143 		snprintf(dn, dnlen, "%sr%s%c", _PATH_DEV, argv[0],
    144 		    RAW_PART + 'a');
    145 		fd = open(dn, O_RDONLY);
    146 		if (fd < 0 && errno == ENOENT) {
    147 			snprintf(dn, dnlen, "%sr%s", _PATH_DEV, argv[0]);
    148 			fd = open(dn, O_RDONLY);
    149 		}
    150 	} else {
    151 		snprintf(dn, dnlen, "%s", argv[0]);
    152 		fd = open(dn, O_RDONLY);
    153 	}
    154 	if (fd < 0)
    155 		err(EXIT_FAILURE, "%s", dn);
    156 	if (ioctl(fd, DIOCGDINFO, &dl))
    157 		err(EXIT_FAILURE, "%s: DIOCGDINFO", dn);
    158 	if (close(fd))
    159 		err(EXIT_FAILURE, "%s", dn);
    160 
    161 	/* Eg: in /dev/fd0c, set devchr to point to the 'f' */
    162 	devchr = strrchr(dn, '/') + 1;
    163 	if (*devchr == 'r')
    164 		++devchr;
    165 
    166 	switch (*devchr) {
    167 		case 'f': /* fd */
    168 			install_fd(dn, &dl);
    169 			break;
    170 		case 'w': /* wd */
    171 			install_wd(dn, &dl);
    172 			setNVpref();
    173 			break;
    174 		case 's': /* sd */
    175 			install_sd(dn, &dl);
    176 			setNVpref();
    177 			break;
    178 		default:
    179 			errx(EXIT_FAILURE,
    180 			     "%s: '%c': Device type not supported.",
    181 			     dn, *devchr);
    182 	}
    183 
    184 	return(EXIT_SUCCESS);
    185 }
    186 
    187 #ifdef CHECK_OS_BOOTVERSION
    188 static void
    189 oscheck(void)
    190 {
    191 	struct nlist kbv[] = {
    192 		{ .n_name = "_bootversion" },
    193 		{ .n_name = NULL }
    194 	};
    195 	kvm_t		*kd_kern;
    196 	char		errbuf[_POSIX2_LINE_MAX];
    197 	u_short		kvers;
    198 	struct stat	sb;
    199 
    200 	if (stat(_PATH_UNIX, &sb) < 0) {
    201 		warnx("Cannot stat %s, no bootversion check done", _PATH_UNIX);
    202 		return;
    203 	}
    204 
    205 	kd_kern = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
    206 	if (kd_kern == NULL)
    207 		errx(EXIT_FAILURE, "kvm_openfiles: %s", errbuf);
    208 	if (kvm_nlist(kd_kern, kbv) == -1)
    209 		errx(EXIT_FAILURE, "kvm_nlist: %s", kvm_geterr(kd_kern));
    210 	if (kbv[0].n_value == 0)
    211 		errx(EXIT_FAILURE, "%s not in namelist", kbv[0].n_name);
    212 	if (kvm_read(kd_kern, kbv[0].n_value, &kvers, sizeof(kvers)) == -1)
    213 		errx(EXIT_FAILURE, "kvm_read: %s", kvm_geterr(kd_kern));
    214 	kvm_close(kd_kern);
    215 	if (kvers != BOOTVERSION)
    216 		errx(EXIT_FAILURE, "Kern bootversion: %d, expected: %d",
    217 		    kvers, BOOTVERSION);
    218 }
    219 #endif
    220 
    221 static void
    222 install_fd(char *devnm, struct disklabel *label)
    223 {
    224 	const char	 *machpath;
    225 	char		 *xxboot, *bootxx;
    226 	struct partition *rootpart;
    227 
    228 	if (label->d_secsize != 512)
    229 		errx(EXIT_FAILURE,
    230 		     "%s: %u: Block size not supported.", devnm,
    231 							  label->d_secsize);
    232 	if (label->d_ntracks != 2)
    233 		errx(EXIT_FAILURE,
    234 		     "%s: Single sided floppy not supported.", devnm);
    235 
    236 	if (milan)
    237 		machpath = milanpath;
    238 	else
    239 		machpath = stdpath;
    240 	size_t xxbootlen = strlen(mdecpath) + strlen(machpath) + 8;
    241 	xxboot = alloca(xxbootlen);
    242 	snprintf(xxboot, xxbootlen, "%s%sfdboot", mdecpath, machpath);
    243 	bootxx = alloca(xxbootlen);
    244 	snprintf(bootxx, xxbootlen, "%s%sbootxx", mdecpath, machpath);
    245 
    246 	/* first used partition (a, b or c) */		/* XXX */
    247 	for (rootpart = label->d_partitions; ; ++rootpart) {
    248 		if (rootpart->p_size)
    249 			break;
    250 	}
    251 	if (rootpart != label->d_partitions) {		/* XXX */
    252 		*(label->d_partitions) = *rootpart;
    253 		memset(rootpart, 0, sizeof(*rootpart));
    254 	}
    255 	label->d_partitions->p_fstype = FS_BSDFFS;	/* XXX */
    256 	label->d_npartitions = 1;
    257 	label->d_checksum = 0;
    258 	label->d_checksum = dkcksum(label);
    259 
    260 	trackpercyl = secpertrack = 0;
    261 	mkbootblock(&bootarea, xxboot, bootxx, label, 0);
    262 
    263 	if (!nowrite) {
    264 		int	fd;
    265 		if ((fd = open(devnm, O_WRONLY)) < 0)
    266 			err(EXIT_FAILURE, "%s", devnm);
    267 		if (write(fd, &bootarea, sizeof(bootarea)) != sizeof(bootarea))
    268 			err(EXIT_FAILURE, "%s", devnm);
    269 		if (close(fd))
    270 			err(EXIT_FAILURE, "%s", devnm);
    271 		if (verbose)
    272 			printf("Boot block installed on %s\n", devnm);
    273 	}
    274 }
    275 
    276 static void
    277 install_sd(char *devnm, struct disklabel *label)
    278 {
    279 	const char	 *machpath;
    280 	char		 *xxb00t, *xxboot, *bootxx;
    281 	struct disklabel rawlabel;
    282 	u_int32_t	 bbsec;
    283 	u_int		 magic;
    284 
    285 	if (label->d_partitions[0].p_size == 0)
    286 		errx(EXIT_FAILURE, "%s: No root-filesystem.", devnm);
    287 	if (label->d_partitions[0].p_fstype != FS_BSDFFS)
    288 		errx(EXIT_FAILURE, "%s: %s: Illegal root-filesystem type.",
    289 		     devnm, fstypenames[label->d_partitions[0].p_fstype]);
    290 
    291 	bbsec = readdisklabel(devnm, &rawlabel);
    292 	if (bbsec == NO_BOOT_BLOCK)
    293 		errx(EXIT_FAILURE, "%s: No NetBSD boot block.", devnm);
    294 	if (memcmp(label, &rawlabel, sizeof(*label)))
    295 		errx(EXIT_FAILURE, "%s: Invalid NetBSD boot block.", devnm);
    296 
    297 	if (milan)
    298 		machpath = milanpath;
    299 	else
    300 		machpath = stdpath;
    301 	if (bbsec) {
    302 		size_t xxb00tlen = strlen(mdecpath) + strlen(machpath) + 14;
    303 		xxb00t = alloca(xxb00tlen);
    304 		snprintf(xxb00t, xxb00tlen, "%s%ssdb00t.ahdi", mdecpath, machpath);
    305 		xxboot = alloca(xxb00tlen);
    306 		snprintf(xxboot, xxb00tlen, "%s%sxxboot.ahdi", mdecpath, machpath);
    307 		magic = AHDIMAGIC;
    308 	} else {
    309 		size_t xxbootlen = strlen(mdecpath) + strlen(machpath) + 8;
    310 		xxb00t = NULL;
    311 		xxboot = alloca(xxbootlen);
    312 		snprintf(xxboot, xxbootlen, "%s%ssdboot", mdecpath, machpath);
    313 		magic = NBDAMAGIC;
    314 	}
    315 	size_t bootxxlen = strlen(mdecpath) + strlen(machpath) + 8;
    316 	bootxx = alloca(bootxxlen);
    317 	snprintf(bootxx, bootxxlen, "%s%sbootxx", mdecpath, machpath);
    318 
    319 	trackpercyl = secpertrack = 0;
    320 	if (xxb00t)
    321 		mkahdiboot(&ahdiboot, xxb00t, devnm, bbsec);
    322 	mkbootblock(&bootarea, xxboot, bootxx, label, magic);
    323 
    324 	if (!nowrite) {
    325 		off_t	bbo = (off_t)bbsec * AHDI_BSIZE;
    326 		int	fd;
    327 
    328 		if ((fd = open(devnm, O_WRONLY)) < 0)
    329 			err(EXIT_FAILURE, "%s", devnm);
    330 		if (lseek(fd, bbo, SEEK_SET) != bbo)
    331 			err(EXIT_FAILURE, "%s", devnm);
    332 		if (write(fd, &bootarea, sizeof(bootarea)) != sizeof(bootarea))
    333 			err(EXIT_FAILURE, "%s", devnm);
    334 		if (verbose)
    335 			printf("Boot block installed on %s (sector %d)\n",
    336 			    devnm, bbsec);
    337 		if (xxb00t) {
    338 			if (lseek(fd, (off_t)0, SEEK_SET) != 0)
    339 				err(EXIT_FAILURE, "%s", devnm);
    340 			if (write(fd, &ahdiboot, sizeof(ahdiboot)) !=
    341 			    sizeof(ahdiboot))
    342 				err(EXIT_FAILURE, "%s", devnm);
    343 			if (verbose)
    344 				printf("AHDI root  installed on %s (0)\n",
    345 				    devnm);
    346 		}
    347 		if (close(fd))
    348 			err(EXIT_FAILURE, "%s", devnm);
    349 	}
    350 }
    351 
    352 static void
    353 install_wd(char *devnm, struct disklabel *label)
    354 {
    355 	const char	 *machpath;
    356 	char		 *xxb00t, *xxboot, *bootxx;
    357 	struct disklabel rawlabel;
    358 	u_int32_t	 bbsec;
    359 	u_int		 magic;
    360 
    361 	if (label->d_partitions[0].p_size == 0)
    362 		errx(EXIT_FAILURE, "%s: No root-filesystem.", devnm);
    363 	if (label->d_partitions[0].p_fstype != FS_BSDFFS)
    364 		errx(EXIT_FAILURE, "%s: %s: Illegal root-filesystem type.",
    365 		     devnm, fstypenames[label->d_partitions[0].p_fstype]);
    366 
    367 	bbsec = readdisklabel(devnm, &rawlabel);
    368 	if (bbsec == NO_BOOT_BLOCK)
    369 		errx(EXIT_FAILURE, "%s: No NetBSD boot block.", devnm);
    370 	if (memcmp(label, &rawlabel, sizeof(*label)))
    371 		errx(EXIT_FAILURE, "%s: Invalid NetBSD boot block.", devnm);
    372 
    373 	if (milan)
    374 		machpath = milanpath;
    375 	else
    376 		machpath = stdpath;
    377 	if (bbsec) {
    378 		size_t xxb00tlen = strlen(mdecpath) + strlen(machpath) + 14;
    379 		xxb00t = alloca(xxb00tlen);
    380 		snprintf(xxb00t, xxb00tlen, "%s%swdb00t.ahdi", mdecpath, machpath);
    381 		xxboot = alloca(xxb00tlen);
    382 		snprintf(xxboot, xxb00tlen, "%s%sxxboot.ahdi", mdecpath, machpath);
    383 		magic = AHDIMAGIC;
    384 	} else {
    385 		size_t xxbootlen = strlen(mdecpath) + strlen(machpath) + 8;
    386 		xxb00t = NULL;
    387 		xxboot = alloca(xxbootlen);
    388 		snprintf(xxboot, xxbootlen, "%s%swdboot", mdecpath, machpath);
    389 		magic = NBDAMAGIC;
    390 	}
    391 	size_t bootxxlen = strlen(mdecpath) + strlen(machpath) + 8;
    392 	bootxx = alloca(bootxxlen);
    393 	snprintf(bootxx, bootxxlen, "%s%sbootxx", mdecpath, machpath);
    394 
    395 	if (xxb00t)
    396 		mkahdiboot(&ahdiboot, xxb00t, devnm, bbsec);
    397 	mkbootblock(&bootarea, xxboot, bootxx, label, magic);
    398 
    399 	if (!nowrite) {
    400 		int	fd;
    401 		off_t	bbo;
    402 
    403 		bbo = (off_t)bbsec * AHDI_BSIZE;
    404 		if ((fd = open(devnm, O_WRONLY)) < 0)
    405 			err(EXIT_FAILURE, "%s", devnm);
    406 		if (lseek(fd, bbo, SEEK_SET) != bbo)
    407 			err(EXIT_FAILURE, "%s", devnm);
    408 		if (write(fd, &bootarea, sizeof(bootarea)) != sizeof(bootarea))
    409 			err(EXIT_FAILURE, "%s", devnm);
    410 		if (verbose)
    411 			printf("Boot block installed on %s (sector %d)\n",
    412 			    devnm, bbsec);
    413 		if (xxb00t) {
    414 			if (lseek(fd, (off_t)0, SEEK_SET) != 0)
    415 				err(EXIT_FAILURE, "%s", devnm);
    416 			if (write(fd, &ahdiboot, sizeof(ahdiboot))
    417 							!= sizeof(ahdiboot))
    418 				err(EXIT_FAILURE, "%s", devnm);
    419 			if (verbose)
    420 				printf("AHDI root installed on %s (sector 0)\n",
    421 				    devnm);
    422 		}
    423 		if (close(fd))
    424 			err(EXIT_FAILURE, "%s", devnm);
    425 	}
    426 }
    427 
    428 static void
    429 mkahdiboot(struct ahdi_root *newroot, char *xxb00t, char *devnm,
    430     u_int32_t bbsec)
    431 {
    432 	struct ahdi_root tmproot;
    433 	struct ahdi_part *pd;
    434 	int		 fd;
    435 
    436 	/* read prototype root-sector */
    437 	if ((fd = open(xxb00t, O_RDONLY)) < 0)
    438 		err(EXIT_FAILURE, "%s", xxb00t);
    439 	if (read(fd, &tmproot, sizeof(tmproot)) != sizeof(tmproot))
    440 		err(EXIT_FAILURE, "%s", xxb00t);
    441 	if (close(fd))
    442 		err(EXIT_FAILURE, "%s", xxb00t);
    443 
    444 	/* set tracks/cylinder and sectors/track */
    445 	setIDEpar(tmproot.ar_fill, sizeof(tmproot.ar_fill));
    446 
    447 	/* read current root-sector */
    448 	if ((fd = open(devnm, O_RDONLY)) < 0)
    449 		err(EXIT_FAILURE, "%s", devnm);
    450 	if (read(fd, newroot, sizeof(*newroot)) != sizeof(*newroot))
    451 		err(EXIT_FAILURE, "%s", devnm);
    452 	if (close(fd))
    453 		err(EXIT_FAILURE, "%s", devnm);
    454 
    455 	/* set bootflags */
    456 	for (pd = newroot->ar_parts; pd-newroot->ar_parts < AHDI_MAXRPD; ++pd) {
    457 		if (pd->ap_st == bbsec) {
    458 			pd->ap_flg = 0x21;	/* bootable, pref = NetBSD */
    459 			goto gotit;
    460 		}
    461 	}
    462 	errx(EXIT_FAILURE,
    463 	     "%s: NetBSD boot block not on primary AHDI partition.", devnm);
    464 
    465 gotit:	/* copy code from prototype and set new checksum */
    466 	memcpy(newroot->ar_fill, tmproot.ar_fill, sizeof(tmproot.ar_fill));
    467 	newroot->ar_checksum = 0;
    468 	newroot->ar_checksum = 0x1234 - abcksum(newroot);
    469 
    470 	if (verbose)
    471 		printf("AHDI      boot loader: %s\n", xxb00t);
    472 }
    473 
    474 static void
    475 mkbootblock(struct bootblock *bb, char *xxb, char *bxx,
    476     struct disklabel *label, u_int magic)
    477 {
    478 	int		 fd;
    479 
    480 	memset(bb, 0, sizeof(*bb));
    481 
    482 	/* set boot block magic */
    483 	bb->bb_magic = magic;
    484 
    485 	/* set disk pack label */
    486 	BBSETLABEL(bb, label);
    487 
    488 	/* set second-stage boot loader */
    489 	if ((fd = open(bxx, O_RDONLY)) < 0)
    490 		err(EXIT_FAILURE, "%s", bxx);
    491 	if (read(fd, bb->bb_bootxx, sizeof(bb->bb_bootxx))
    492 					!= sizeof(bb->bb_bootxx))
    493 		err(EXIT_FAILURE, "%s", bxx);
    494 	if (close(fd))
    495 		err(EXIT_FAILURE, "%s", bxx);
    496 
    497 	/* set first-stage bootloader */
    498 	if ((fd = open(xxb, O_RDONLY)) < 0)
    499 		err(EXIT_FAILURE, "%s", xxb);
    500 	if (read(fd, bb->bb_xxboot, sizeof(bb->bb_xxboot))
    501 					!= sizeof(bb->bb_xxboot))
    502 		err(EXIT_FAILURE, "%s", xxb);
    503 	if (close(fd))
    504 		err(EXIT_FAILURE, "%s", xxb);
    505 
    506 	/* set tracks/cylinder and sectors/track */
    507 	setIDEpar(bb->bb_xxboot, sizeof(bb->bb_xxboot));
    508 
    509 	/* set AHDI checksum */
    510 	*((u_int16_t *)bb->bb_xxboot + 255) = 0;
    511 	*((u_int16_t *)bb->bb_xxboot + 255) = 0x1234 - abcksum(bb->bb_xxboot);
    512 
    513 	if (verbose) {
    514 		printf("Primary   boot loader: %s\n", xxb);
    515 		printf("Secondary boot loader: %s\n", bxx);
    516 	}
    517 }
    518 
    519 static void
    520 setIDEpar (u_int8_t *start, size_t size)
    521 {
    522 	static const u_int8_t	mark[] = { 'N', 'e', 't', 'B', 'S', 'D' };
    523 
    524 	if ((u_int)trackpercyl > 255)
    525 		errx(EXIT_FAILURE,
    526 		     "%d: Illegal tracks/cylinder value (1..255)", trackpercyl);
    527 	if ((u_int)secpertrack > 255)
    528 		errx(EXIT_FAILURE,
    529 		     "%d: Illegal sectors/track value (1..255)", secpertrack);
    530 
    531 	if (trackpercyl || secpertrack) {
    532 		u_int8_t *p;
    533 
    534 		if (!trackpercyl)
    535 			errx(EXIT_FAILURE, "Need tracks/cylinder too.");
    536 		if (!secpertrack)
    537 			errx(EXIT_FAILURE, "Need sectors/track too.");
    538 
    539 		start += 2;
    540 		size  -= sizeof(mark) + 2;
    541 		for (p = start + size; p >= start; --p) {
    542 			if (*p != *mark)
    543 				continue;
    544 			if (!memcmp(p, mark, sizeof(mark)))
    545 				break;
    546 		}
    547 		if (p < start)
    548 			errx(EXIT_FAILURE,
    549 			     "Malformatted xxboot prototype.");
    550 
    551 		*--p = secpertrack;
    552 		*--p = trackpercyl;
    553 
    554 		if (verbose) {
    555 			printf("sectors/track  : %d\n", secpertrack);
    556 			printf("tracks/cylinder: %d\n", trackpercyl);
    557 		}
    558 	}
    559 }
    560 
    561 static void
    562 setNVpref(void)
    563 {
    564 	static const u_char	bootpref = BOOTPREF_NETBSD;
    565 	static const char	nvrdev[] = PATH_NVRAM;
    566 
    567 	if (!nowrite) {
    568 		int	fd;
    569 
    570 		if ((fd = open(nvrdev, O_RDWR)) < 0)
    571 			err(EXIT_FAILURE, "%s", nvrdev);
    572 		if (lseek(fd, (off_t)1, SEEK_SET) != 1)
    573 			err(EXIT_FAILURE, "%s", nvrdev);
    574 		if (write(fd, &bootpref, (size_t)1) != 1)
    575 			err(EXIT_FAILURE, "%s", nvrdev);
    576 		if (close(fd))
    577 			err(EXIT_FAILURE, "%s", nvrdev);
    578 		if (verbose)
    579 			printf("Boot preference set to NetBSD.\n");
    580 	}
    581 }
    582 
    583 static u_int
    584 abcksum (void *bs)
    585 {
    586 	u_int16_t sum  = 0,
    587 		  *st  = (u_int16_t *)bs,
    588 		  *end = (u_int16_t *)bs + 256;
    589 
    590 	while (st < end)
    591 		sum += *st++;
    592 	return(sum);
    593 }
    594