xref: /netbsd-src/sys/arch/atari/stand/installboot/installboot.c (revision 95b39c65ca575fb40c6bb7083e0eb7ec28eabef1)
1 /*	$NetBSD: installboot.c,v 1.35 2015/08/12 17:59:51 tsutsui 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