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