Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / atari / stand / installboot / installboot.c
blob08c48ff3d5b3d7cda81f5bee94c0e2181dae7bed
1 /* $NetBSD: installboot.c,v 1.23 2009/03/14 14:45:57 dsl Exp $ */
3 /*
4 * Copyright (c) 1995 Waldi Ravens
5 * All rights reserved.
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
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.
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>
49 #define DKTYPENAMES
50 #define FSTYPENAMES
51 #include <sys/disklabel.h>
52 #include <machine/ahdilabel.h>
54 #include "installboot.h"
56 static void usage(void);
57 static void oscheck(void);
58 static u_int abcksum(void *);
59 static void setNVpref(void);
60 static void setIDEpar(u_int8_t *, size_t);
61 static void mkahdiboot(struct ahdi_root *, char *,
62 char *, u_int32_t);
63 static void mkbootblock(struct bootblock *, char *,
64 char *, struct disklabel *, u_int);
65 static void install_fd(char *, struct disklabel *);
66 static void install_sd(char *, struct disklabel *);
67 static void install_wd(char *, struct disklabel *);
69 static struct bootblock bootarea;
70 static struct ahdi_root ahdiboot;
71 static const char mdecpath[] = PATH_MDEC;
72 static const char stdpath[] = PATH_STD;
73 static const char milanpath[] = PATH_MILAN;
74 static int nowrite = 0;
75 static int verbose = 0;
76 static int trackpercyl = 0;
77 static int secpertrack = 0;
78 static int milan = 0;
80 static void
81 usage ()
83 fprintf(stderr,
84 "usage: installboot [options] device\n"
85 "where options are:\n"
86 "\t-N do not actually write anything on the disk\n"
87 "\t-m use Milan boot blocks\n"
88 "\t-t number of tracks per cylinder (IDE disk)\n"
89 "\t-u number of sectors per track (IDE disk)\n"
90 "\t-v verbose mode\n");
91 exit(EXIT_FAILURE);
94 int
95 main (int argc, char *argv[])
97 struct disklabel dl;
98 char *dn;
99 char *devchr;
100 int fd, c;
102 /* check OS bootversion */
103 oscheck();
105 /* parse options */
106 while ((c = getopt(argc, argv, "Nmt:u:v")) != -1) {
107 switch (c) {
108 case 'N':
109 nowrite = 1;
110 break;
111 case 'm':
112 milan = 1;
113 break;
114 case 't':
115 trackpercyl = atoi(optarg);
116 break;
117 case 'u':
118 secpertrack = atoi(optarg);
119 break;
120 case 'v':
121 verbose = 1;
122 break;
123 default:
124 usage();
127 argv += optind;
128 argc -= optind;
129 if (argc != 1)
130 usage();
132 /* get disk label */
133 dn = alloca(sizeof(_PATH_DEV) + strlen(argv[0]) + 8);
134 if (!strchr(argv[0], '/')) {
135 sprintf(dn, "%sr%s%c", _PATH_DEV, argv[0], RAW_PART + 'a');
136 fd = open(dn, O_RDONLY);
137 if (fd < 0 && errno == ENOENT) {
138 sprintf(dn, "%sr%s", _PATH_DEV, argv[0]);
139 fd = open(dn, O_RDONLY);
141 } else {
142 sprintf(dn, "%s", argv[0]);
143 fd = open(dn, O_RDONLY);
145 if (fd < 0)
146 err(EXIT_FAILURE, "%s", dn);
147 if (ioctl(fd, DIOCGDINFO, &dl))
148 err(EXIT_FAILURE, "%s: DIOCGDINFO", dn);
149 if (close(fd))
150 err(EXIT_FAILURE, "%s", dn);
152 /* Eg: in /dev/fd0c, set devchr to point to the 'f' */
153 devchr = strrchr(dn, '/') + 1;
154 if (*devchr == 'r')
155 ++devchr;
157 switch (*devchr) {
158 case 'f': /* fd */
159 install_fd(dn, &dl);
160 break;
161 case 'w': /* wd */
162 install_wd(dn, &dl);
163 setNVpref();
164 break;
165 case 's': /* sd */
166 install_sd(dn, &dl);
167 setNVpref();
168 break;
169 default:
170 errx(EXIT_FAILURE,
171 "%s: '%c': Device type not supported.",
172 dn, *devchr);
175 return(EXIT_SUCCESS);
178 static void
179 oscheck ()
181 struct nlist kbv[] = { { "_bootversion" },
182 { NULL } };
183 kvm_t *kd_kern;
184 char errbuf[_POSIX2_LINE_MAX];
185 u_short kvers;
186 struct stat sb;
188 if (stat(_PATH_UNIX, &sb) < 0) {
189 warnx("Cannot stat %s, no bootversion check done", _PATH_UNIX);
190 return;
193 kd_kern = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
194 if (kd_kern == NULL)
195 errx(EXIT_FAILURE, "kvm_openfiles: %s", errbuf);
196 if (kvm_nlist(kd_kern, kbv) == -1)
197 errx(EXIT_FAILURE, "kvm_nlist: %s", kvm_geterr(kd_kern));
198 if (kbv[0].n_value == 0)
199 errx(EXIT_FAILURE, "%s not in namelist", kbv[0].n_name);
200 if (kvm_read(kd_kern, kbv[0].n_value, (char *)&kvers,
201 sizeof(kvers)) == -1)
202 errx(EXIT_FAILURE, "kvm_read: %s", kvm_geterr(kd_kern));
203 kvm_close(kd_kern);
204 if (kvers != BOOTVERSION)
205 errx(EXIT_FAILURE, "Kern bootversion: %d, expected: %d",
206 kvers, BOOTVERSION);
209 static void
210 install_fd (char *devnm, struct disklabel *label)
212 const char *machpath;
213 char *xxboot, *bootxx;
214 struct partition *rootpart;
216 if (label->d_secsize != 512)
217 errx(EXIT_FAILURE,
218 "%s: %u: Block size not supported.", devnm,
219 label->d_secsize);
220 if (label->d_ntracks != 2)
221 errx(EXIT_FAILURE,
222 "%s: Single sided floppy not supported.", devnm);
224 if (milan)
225 machpath = milanpath;
226 else
227 machpath = stdpath;
228 xxboot = alloca(strlen(mdecpath) + strlen(machpath) + 8);
229 sprintf(xxboot, "%s%sfdboot", mdecpath, machpath);
230 bootxx = alloca(strlen(mdecpath) + strlen(machpath) + 8);
231 sprintf(bootxx, "%s%sbootxx", mdecpath, machpath);
233 /* first used partition (a, b or c) */ /* XXX */
234 for (rootpart = label->d_partitions; ; ++rootpart) {
235 if (rootpart->p_size)
236 break;
238 if (rootpart != label->d_partitions) { /* XXX */
239 *(label->d_partitions) = *rootpart;
240 memset(rootpart, 0, sizeof(*rootpart));
242 label->d_partitions->p_fstype = FS_BSDFFS; /* XXX */
243 label->d_npartitions = 1;
244 label->d_checksum = 0;
245 label->d_checksum = dkcksum(label);
247 trackpercyl = secpertrack = 0;
248 mkbootblock(&bootarea, xxboot, bootxx, label, 0);
250 if (!nowrite) {
251 int fd;
252 if ((fd = open(devnm, O_WRONLY)) < 0)
253 err(EXIT_FAILURE, "%s", devnm);
254 if (write(fd, &bootarea, sizeof(bootarea)) != sizeof(bootarea))
255 err(EXIT_FAILURE, "%s", devnm);
256 if (close(fd))
257 err(EXIT_FAILURE, "%s", devnm);
258 if (verbose)
259 printf("Boot block installed on %s\n", devnm);
263 static void
264 install_sd (char *devnm, struct disklabel *label)
266 const char *machpath;
267 char *xxb00t, *xxboot, *bootxx;
268 struct disklabel rawlabel;
269 u_int32_t bbsec;
270 u_int magic;
272 if (label->d_partitions[0].p_size == 0)
273 errx(EXIT_FAILURE, "%s: No root-filesystem.", devnm);
274 if (label->d_partitions[0].p_fstype != FS_BSDFFS)
275 errx(EXIT_FAILURE, "%s: %s: Illegal root-filesystem type.",
276 devnm, fstypenames[label->d_partitions[0].p_fstype]);
278 bbsec = readdisklabel(devnm, &rawlabel);
279 if (bbsec == NO_BOOT_BLOCK)
280 errx(EXIT_FAILURE, "%s: No NetBSD boot block.", devnm);
281 if (memcmp(label, &rawlabel, sizeof(*label)))
282 errx(EXIT_FAILURE, "%s: Invalid NetBSD boot block.", devnm);
284 if (milan)
285 machpath = milanpath;
286 else
287 machpath = stdpath;
288 if (bbsec) {
289 xxb00t = alloca(strlen(mdecpath) + strlen(machpath) + 14);
290 sprintf(xxb00t, "%s%ssdb00t.ahdi", mdecpath, machpath);
291 xxboot = alloca(strlen(mdecpath) + strlen(machpath) + 14);
292 sprintf(xxboot, "%s%sxxboot.ahdi", mdecpath, machpath);
293 magic = AHDIMAGIC;
294 } else {
295 xxb00t = NULL;
296 xxboot = alloca(strlen(mdecpath) + strlen(machpath) + 8);
297 sprintf(xxboot, "%s%ssdboot", mdecpath, machpath);
298 magic = NBDAMAGIC;
300 bootxx = alloca(strlen(mdecpath) + strlen(machpath) + 8);
301 sprintf(bootxx, "%s%sbootxx", mdecpath, machpath);
303 trackpercyl = secpertrack = 0;
304 if (xxb00t)
305 mkahdiboot(&ahdiboot, xxb00t, devnm, bbsec);
306 mkbootblock(&bootarea, xxboot, bootxx, label, magic);
308 if (!nowrite) {
309 off_t bbo = (off_t)bbsec * AHDI_BSIZE;
310 int fd;
312 if ((fd = open(devnm, O_WRONLY)) < 0)
313 err(EXIT_FAILURE, "%s", devnm);
314 if (lseek(fd, bbo, SEEK_SET) != bbo)
315 err(EXIT_FAILURE, "%s", devnm);
316 if (write(fd, &bootarea, sizeof(bootarea)) != sizeof(bootarea))
317 err(EXIT_FAILURE, "%s", devnm);
318 if (verbose)
319 printf("Boot block installed on %s (sector %d)\n", devnm,
320 bbsec);
321 if (xxb00t) {
322 if (lseek(fd, (off_t)0, SEEK_SET) != 0)
323 err(EXIT_FAILURE, "%s", devnm);
324 if (write(fd, &ahdiboot, sizeof(ahdiboot)) != sizeof(ahdiboot))
325 err(EXIT_FAILURE, "%s", devnm);
326 if (verbose)
327 printf("AHDI root installed on %s (0)\n",
328 devnm);
330 if (close(fd))
331 err(EXIT_FAILURE, "%s", devnm);
335 static void
336 install_wd (char *devnm, struct disklabel *label)
338 const char *machpath;
339 char *xxb00t, *xxboot, *bootxx;
340 struct disklabel rawlabel;
341 u_int32_t bbsec;
342 u_int magic;
344 if (label->d_partitions[0].p_size == 0)
345 errx(EXIT_FAILURE, "%s: No root-filesystem.", devnm);
346 if (label->d_partitions[0].p_fstype != FS_BSDFFS)
347 errx(EXIT_FAILURE, "%s: %s: Illegal root-filesystem type.",
348 devnm, fstypenames[label->d_partitions[0].p_fstype]);
350 bbsec = readdisklabel(devnm, &rawlabel);
351 if (bbsec == NO_BOOT_BLOCK)
352 errx(EXIT_FAILURE, "%s: No NetBSD boot block.", devnm);
353 if (memcmp(label, &rawlabel, sizeof(*label)))
354 errx(EXIT_FAILURE, "%s: Invalid NetBSD boot block.", devnm);
356 if (milan)
357 machpath = milanpath;
358 else
359 machpath = stdpath;
360 if (bbsec) {
361 xxb00t = alloca(strlen(mdecpath) + strlen(machpath) + 14);
362 sprintf(xxb00t, "%s%swdb00t.ahdi", mdecpath, machpath);
363 xxboot = alloca(strlen(mdecpath) + strlen(machpath) + 14);
364 sprintf(xxboot, "%s%sxxboot.ahdi", mdecpath, machpath);
365 magic = AHDIMAGIC;
366 } else {
367 xxb00t = NULL;
368 xxboot = alloca(strlen(mdecpath) + strlen(machpath) + 8);
369 sprintf(xxboot, "%s%swdboot", mdecpath, machpath);
370 magic = NBDAMAGIC;
372 bootxx = alloca(strlen(mdecpath) + strlen(machpath) + 8);
373 sprintf(bootxx, "%s%sbootxx", mdecpath, machpath);
375 if (xxb00t)
376 mkahdiboot(&ahdiboot, xxb00t, devnm, bbsec);
377 mkbootblock(&bootarea, xxboot, bootxx, label, magic);
379 if (!nowrite) {
380 int fd;
381 off_t bbo;
383 bbo = (off_t)bbsec * AHDI_BSIZE;
384 if ((fd = open(devnm, O_WRONLY)) < 0)
385 err(EXIT_FAILURE, "%s", devnm);
386 if (lseek(fd, bbo, SEEK_SET) != bbo)
387 err(EXIT_FAILURE, "%s", devnm);
388 if (write(fd, &bootarea, sizeof(bootarea)) != sizeof(bootarea))
389 err(EXIT_FAILURE, "%s", devnm);
390 if (verbose)
391 printf("Boot block installed on %s (sector %d)\n", devnm,
392 bbsec);
393 if (xxb00t) {
394 if (lseek(fd, (off_t)0, SEEK_SET) != 0)
395 err(EXIT_FAILURE, "%s", devnm);
396 if (write(fd, &ahdiboot, sizeof(ahdiboot))
397 != sizeof(ahdiboot))
398 err(EXIT_FAILURE, "%s", devnm);
399 if (verbose)
400 printf("AHDI root installed on %s (sector 0)\n",
401 devnm);
403 if (close(fd))
404 err(EXIT_FAILURE, "%s", devnm);
408 static void
409 mkahdiboot (newroot, xxb00t, devnm, bbsec)
410 struct ahdi_root *newroot;
411 char *xxb00t,
412 *devnm;
413 u_int32_t bbsec;
415 struct ahdi_root tmproot;
416 struct ahdi_part *pd;
417 int fd;
419 /* read prototype root-sector */
420 if ((fd = open(xxb00t, O_RDONLY)) < 0)
421 err(EXIT_FAILURE, "%s", xxb00t);
422 if (read(fd, &tmproot, sizeof(tmproot)) != sizeof(tmproot))
423 err(EXIT_FAILURE, "%s", xxb00t);
424 if (close(fd))
425 err(EXIT_FAILURE, "%s", xxb00t);
427 /* set tracks/cylinder and sectors/track */
428 setIDEpar(tmproot.ar_fill, sizeof(tmproot.ar_fill));
430 /* read current root-sector */
431 if ((fd = open(devnm, O_RDONLY)) < 0)
432 err(EXIT_FAILURE, "%s", devnm);
433 if (read(fd, newroot, sizeof(*newroot)) != sizeof(*newroot))
434 err(EXIT_FAILURE, "%s", devnm);
435 if (close(fd))
436 err(EXIT_FAILURE, "%s", devnm);
438 /* set bootflags */
439 for (pd = newroot->ar_parts; pd-newroot->ar_parts < AHDI_MAXRPD; ++pd) {
440 if (pd->ap_st == bbsec) {
441 pd->ap_flg = 0x21; /* bootable, pref = NetBSD */
442 goto gotit;
445 errx(EXIT_FAILURE,
446 "%s: NetBSD boot block not on primary AHDI partition.", devnm);
448 gotit: /* copy code from prototype and set new checksum */
449 memcpy(newroot->ar_fill, tmproot.ar_fill, sizeof(tmproot.ar_fill));
450 newroot->ar_checksum = 0;
451 newroot->ar_checksum = 0x1234 - abcksum(newroot);
453 if (verbose)
454 printf("AHDI boot loader: %s\n", xxb00t);
457 static void
458 mkbootblock (bb, xxb, bxx, label, magic)
459 struct bootblock *bb;
460 char *xxb,
461 *bxx;
462 u_int magic;
463 struct disklabel *label;
465 int fd;
467 memset(bb, 0, sizeof(*bb));
469 /* set boot block magic */
470 bb->bb_magic = magic;
472 /* set disk pack label */
473 BBSETLABEL(bb, label);
475 /* set second-stage boot loader */
476 if ((fd = open(bxx, O_RDONLY)) < 0)
477 err(EXIT_FAILURE, "%s", bxx);
478 if (read(fd, bb->bb_bootxx, sizeof(bb->bb_bootxx))
479 != sizeof(bb->bb_bootxx))
480 err(EXIT_FAILURE, "%s", bxx);
481 if (close(fd))
482 err(EXIT_FAILURE, "%s", bxx);
484 /* set first-stage bootloader */
485 if ((fd = open(xxb, O_RDONLY)) < 0)
486 err(EXIT_FAILURE, "%s", xxb);
487 if (read(fd, bb->bb_xxboot, sizeof(bb->bb_xxboot))
488 != sizeof(bb->bb_xxboot))
489 err(EXIT_FAILURE, "%s", xxb);
490 if (close(fd))
491 err(EXIT_FAILURE, "%s", xxb);
493 /* set tracks/cylinder and sectors/track */
494 setIDEpar(bb->bb_xxboot, sizeof(bb->bb_xxboot));
496 /* set AHDI checksum */
497 *((u_int16_t *)bb->bb_xxboot + 255) = 0;
498 *((u_int16_t *)bb->bb_xxboot + 255) = 0x1234 - abcksum(bb->bb_xxboot);
500 if (verbose) {
501 printf("Primary boot loader: %s\n", xxb);
502 printf("Secondary boot loader: %s\n", bxx);
506 static void
507 setIDEpar (u_int8_t *start, size_t size)
509 static const u_int8_t mark[] = { 'N', 'e', 't', 'B', 'S', 'D' };
511 if ((u_int)trackpercyl > 255)
512 errx(EXIT_FAILURE,
513 "%d: Illegal tracks/cylinder value (1..255)", trackpercyl);
514 if ((u_int)secpertrack > 255)
515 errx(EXIT_FAILURE,
516 "%d: Illegal sectors/track value (1..255)", secpertrack);
518 if (trackpercyl || secpertrack) {
519 u_int8_t *p;
521 if (!trackpercyl)
522 errx(EXIT_FAILURE, "Need tracks/cylinder too.");
523 if (!secpertrack)
524 errx(EXIT_FAILURE, "Need sectors/track too.");
526 start += 2;
527 size -= sizeof(mark) + 2;
528 for (p = start + size; p >= start; --p) {
529 if (*p != *mark)
530 continue;
531 if (!memcmp(p, mark, sizeof(mark)))
532 break;
534 if (p < start)
535 errx(EXIT_FAILURE,
536 "Malformatted xxboot prototype.");
538 *--p = secpertrack;
539 *--p = trackpercyl;
541 if (verbose) {
542 printf("sectors/track : %d\n", secpertrack);
543 printf("tracks/cylinder: %d\n", trackpercyl);
548 static void
549 setNVpref ()
551 static const u_char bootpref = BOOTPREF_NETBSD;
552 static const char nvrdev[] = PATH_NVRAM;
554 if (!nowrite) {
555 int fd;
557 if ((fd = open(nvrdev, O_RDWR)) < 0)
558 err(EXIT_FAILURE, "%s", nvrdev);
559 if (lseek(fd, (off_t)1, SEEK_SET) != 1)
560 err(EXIT_FAILURE, "%s", nvrdev);
561 if (write(fd, &bootpref, (size_t)1) != 1)
562 err(EXIT_FAILURE, "%s", nvrdev);
563 if (close(fd))
564 err(EXIT_FAILURE, "%s", nvrdev);
565 if (verbose)
566 printf("Boot preference set to NetBSD.\n");
570 static u_int
571 abcksum (void *bs)
573 u_int16_t sum = 0,
574 *st = (u_int16_t *)bs,
575 *end = (u_int16_t *)bs + 256;
577 while (st < end)
578 sum += *st++;
579 return(sum);