Annotation of sys/arch/mvme68k/stand/installboot/installboot.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: installboot.c,v 1.11 2007/06/17 00:28:56 deraadt Exp $ */
! 2: /* $NetBSD: installboot.c,v 1.5 1995/11/17 23:23:50 gwr Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1994 Paul Kranenburg
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed by Paul Kranenburg.
! 19: * 4. The name of the author may not be used to endorse or promote products
! 20: * derived from this software without specific prior written permission
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 32: */
! 33:
! 34: #include <sys/param.h>
! 35: #include <sys/mount.h>
! 36: #include <sys/time.h>
! 37: #include <sys/stat.h>
! 38: #include <sys/disklabel.h>
! 39: #include <ufs/ufs/dinode.h>
! 40: #include <ufs/ufs/dir.h>
! 41: #include <ufs/ffs/fs.h>
! 42: #include <err.h>
! 43: #include <a.out.h>
! 44: #include <fcntl.h>
! 45: #include <nlist.h>
! 46: #include <stdlib.h>
! 47: #include <stdio.h>
! 48: #include <string.h>
! 49: #include <unistd.h>
! 50: #include <util.h>
! 51:
! 52: int verbose, nowrite, hflag;
! 53: char *boot, *proto, *dev;
! 54: char cdev[80];
! 55:
! 56: struct nlist nl[] = {
! 57: #define X_BLOCK_SIZE 0
! 58: {"_block_size"},
! 59: #define X_BLOCK_COUNT 1
! 60: {"_block_count"},
! 61: #define X_BLOCK_TABLE 2
! 62: {"_block_table"},
! 63: {NULL}
! 64: };
! 65:
! 66: int *block_size_p; /* block size var. in prototype image */
! 67: int *block_count_p; /* block count var. in prototype image */
! 68: daddr_t *block_table; /* block number array in prototype image */
! 69: int maxblocknum; /* size of this array */
! 70:
! 71:
! 72: char *loadprotoblocks(char *, long *);
! 73: int loadblocknums(char *, int);
! 74: static void devread(int, void *, daddr_t, size_t, char *);
! 75: static void usage(void);
! 76: int main(int, char *[]);
! 77: static void vid_to_disklabel(char *, char *);
! 78:
! 79: static void
! 80: usage(void)
! 81: {
! 82: fprintf(stderr,
! 83: "usage: installboot [-n] [-v] [-h] <boot> <proto> <device>\n");
! 84: exit(1);
! 85: }
! 86:
! 87: int
! 88: main(argc, argv)
! 89: int argc;
! 90: char *argv[];
! 91: {
! 92: int c, devfd;
! 93: char *protostore;
! 94: long protosize;
! 95:
! 96: while ((c = getopt(argc, argv, "vnh")) != -1) {
! 97: switch (c) {
! 98: case 'h':
! 99: /* Don't strip a.out header */
! 100: hflag = 1;
! 101: break;
! 102: case 'n':
! 103: /* Do not actually write the bootblock to disk */
! 104: nowrite = 1;
! 105: break;
! 106: case 'v':
! 107: /* Chat */
! 108: verbose = 1;
! 109: break;
! 110: default:
! 111: usage();
! 112: }
! 113: }
! 114:
! 115: if (argc - optind < 3) {
! 116: usage();
! 117: }
! 118:
! 119: boot = argv[optind];
! 120: proto = argv[optind + 1];
! 121: dev = argv[optind + 2];
! 122: strlcpy(cdev, dev, sizeof cdev);
! 123: cdev[strlen(cdev)-1] = 'c';
! 124:
! 125: if (verbose) {
! 126: printf("boot: %s\n", boot);
! 127: printf("proto: %s\n", proto);
! 128: printf("device: %s\n", dev);
! 129: printf("cdevice: %s\n", cdev);
! 130: }
! 131:
! 132: /* Insert VID into disklabel */
! 133: vid_to_disklabel(cdev, proto);
! 134:
! 135: /* Load proto blocks into core */
! 136: if ((protostore = loadprotoblocks(proto, &protosize)) == NULL)
! 137: exit(1);
! 138:
! 139: /* XXX - Paranoia: Make sure size is aligned! */
! 140: if (protosize & (DEV_BSIZE - 1))
! 141: err(1, "proto bootblock bad size=%d", protosize);
! 142:
! 143: /* Open and check raw disk device */
! 144: if ((devfd = open(dev, O_RDONLY, 0)) < 0)
! 145: err(1, "open: %s", dev);
! 146:
! 147: /* Extract and load block numbers */
! 148: if (loadblocknums(boot, devfd) != 0)
! 149: exit(1);
! 150:
! 151: (void)close(devfd);
! 152:
! 153: if (nowrite)
! 154: return 0;
! 155:
! 156: /* Write patched proto bootblocks into the superblock */
! 157: if (protosize > SBSIZE - DEV_BSIZE)
! 158: errx(1, "proto bootblocks too big");
! 159:
! 160: if ((devfd = open(cdev, O_RDWR, 0)) < 0)
! 161: err(1, "open: %s", dev);
! 162:
! 163: if (lseek(devfd, DEV_BSIZE, SEEK_SET) != DEV_BSIZE)
! 164: err(1, "lseek bootstrap");
! 165:
! 166: /* Sync filesystems (to clean in-memory superblock?) */
! 167: sync();
! 168:
! 169: if (write(devfd, protostore, protosize) != protosize)
! 170: err(1, "write bootstrap");
! 171: (void)close(devfd);
! 172: return 0;
! 173: }
! 174:
! 175: char *
! 176: loadprotoblocks(fname, size)
! 177: char *fname;
! 178: long *size;
! 179: {
! 180: int fd;
! 181: size_t tdsize; /* text+data size */
! 182: size_t bbsize; /* boot block size (block aligned) */
! 183: char *bp;
! 184: struct nlist *nlp;
! 185: struct exec eh;
! 186: long off;
! 187:
! 188: fd = -1;
! 189: bp = NULL;
! 190:
! 191: /* Locate block number array in proto file */
! 192: if (nlist(fname, nl) != 0) {
! 193: warnx("nlist: %s: symbols not found", fname);
! 194: return NULL;
! 195: }
! 196: /* Validate symbol types (global data). */
! 197: for (nlp = nl; nlp->n_un.n_name; nlp++) {
! 198: if (nlp->n_type != (N_DATA | N_EXT)) {
! 199: warnx("nlist: %s: wrong type", nlp->n_un.n_name);
! 200: return NULL;
! 201: }
! 202: }
! 203:
! 204: if ((fd = open(fname, O_RDONLY)) < 0) {
! 205: warn("open: %s", fname);
! 206: return NULL;
! 207: }
! 208: if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) {
! 209: warn("read: %s", fname);
! 210: goto bad;
! 211: }
! 212: if (N_GETMAGIC(eh) != OMAGIC) {
! 213: warn("bad magic: 0x%x", eh.a_midmag);
! 214: goto bad;
! 215: }
! 216: /*
! 217: * We have to include the exec header in the beginning of
! 218: * the buffer, and leave extra space at the end in case
! 219: * the actual write to disk wants to skip the header.
! 220: */
! 221: tdsize = eh.a_text + eh.a_data;
! 222: bbsize = tdsize + sizeof(eh);
! 223: bbsize = roundup(bbsize, DEV_BSIZE);
! 224:
! 225: /*
! 226: * Allocate extra space here because the caller may copy
! 227: * the boot block starting at the end of the exec header.
! 228: * This prevents reading beyond the end of the buffer.
! 229: */
! 230: if ((bp = calloc(bbsize + sizeof(eh), 1)) == NULL) {
! 231: warnx("malloc: %s: no memory", fname);
! 232: goto bad;
! 233: }
! 234: /* Copy the exec header and read the rest of the file. */
! 235: memcpy(bp, &eh, sizeof(eh));
! 236: if (read(fd, bp+sizeof(eh), tdsize) != tdsize) {
! 237: warn("read: %s", fname);
! 238: goto bad;
! 239: }
! 240:
! 241: *size = bbsize; /* aligned to DEV_BSIZE */
! 242:
! 243: /* Calculate the symbols' locations within the proto file */
! 244: off = N_DATOFF(eh) - N_DATADDR(eh) - (eh.a_entry - N_TXTADDR(eh));
! 245: block_size_p = (int *) (bp + nl[X_BLOCK_SIZE ].n_value + off);
! 246: block_count_p = (int *) (bp + nl[X_BLOCK_COUNT].n_value + off);
! 247: block_table = (daddr_t *) (bp + nl[X_BLOCK_TABLE].n_value + off);
! 248: maxblocknum = *block_count_p;
! 249:
! 250: if (verbose) {
! 251: printf("%s: entry point %#x\n", fname, eh.a_entry);
! 252: printf("proto bootblock size %ld\n", *size);
! 253: printf("room for %d filesystem blocks at %#x\n",
! 254: maxblocknum, nl[X_BLOCK_TABLE].n_value);
! 255: }
! 256:
! 257: close(fd);
! 258: if (!hflag)
! 259: bp += sizeof(struct exec);
! 260: return bp;
! 261:
! 262: bad:
! 263: if (bp)
! 264: free(bp);
! 265: if (fd >= 0)
! 266: close(fd);
! 267: return NULL;
! 268: }
! 269:
! 270: static void
! 271: devread(int fd, void *buf, daddr_t blk, size_t size, char *msg)
! 272: {
! 273: if (lseek(fd, dbtob(blk), SEEK_SET) != dbtob(blk))
! 274: err(1, "%s: devread: lseek", msg);
! 275:
! 276: if (read(fd, buf, size) != size)
! 277: err(1, "%s: devread: read", msg);
! 278: }
! 279:
! 280: static char sblock[SBSIZE];
! 281:
! 282: int
! 283: loadblocknums(char *boot, int devfd)
! 284: {
! 285: int i, fd;
! 286: struct stat statbuf;
! 287: struct statfs statfsbuf;
! 288: struct fs *fs;
! 289: char *buf;
! 290: daddr_t blk, *ap;
! 291: struct ufs1_dinode *ip;
! 292: int ndb;
! 293:
! 294: /*
! 295: * Open 2nd-level boot program and record the block numbers
! 296: * it occupies on the filesystem represented by `devfd'.
! 297: */
! 298:
! 299: /* Make sure the (probably new) boot file is on disk. */
! 300: sync(); sleep(1);
! 301:
! 302: if ((fd = open(boot, O_RDONLY)) < 0)
! 303: err(1, "open: %s", boot);
! 304:
! 305: if (fstatfs(fd, &statfsbuf) != 0)
! 306: err(1, "statfs: %s", boot);
! 307:
! 308: if (strncmp(statfsbuf.f_fstypename, "ffs", MFSNAMELEN) &&
! 309: strncmp(statfsbuf.f_fstypename, "ufs", MFSNAMELEN) ) {
! 310: errx(1, "%s: must be on an FFS filesystem", boot);
! 311: }
! 312:
! 313: if (fsync(fd) != 0)
! 314: err(1, "fsync: %s", boot);
! 315:
! 316: if (fstat(fd, &statbuf) != 0)
! 317: err(1, "fstat: %s", boot);
! 318:
! 319: close(fd);
! 320:
! 321: /* Read superblock */
! 322: devread(devfd, sblock, SBLOCK, SBSIZE, "superblock");
! 323: fs = (struct fs *)sblock;
! 324:
! 325: /* Sanity-check super-block. */
! 326:
! 327: if (fs->fs_magic != FS_MAGIC)
! 328: errx(1, "Bad magic number in superblock");
! 329:
! 330: if (fs->fs_inopb <= 0)
! 331: err(1, "Bad inopb=%d in superblock", fs->fs_inopb);
! 332:
! 333: /* Read inode */
! 334: if ((buf = malloc(fs->fs_bsize)) == NULL)
! 335: errx(1, "No memory for filesystem block");
! 336:
! 337: blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));
! 338: devread(devfd, buf, blk, fs->fs_bsize, "inode");
! 339: ip = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino);
! 340:
! 341: /*
! 342: * Have the inode. Figure out how many blocks we need.
! 343: */
! 344: ndb = howmany(ip->di_size, fs->fs_bsize);
! 345: if (ndb > maxblocknum)
! 346: errx(1, "Too many blocks");
! 347: *block_count_p = ndb;
! 348: *block_size_p = fs->fs_bsize;
! 349: if (verbose)
! 350: printf("Will load %d blocks of size %d each.\n",
! 351: ndb, fs->fs_bsize);
! 352:
! 353: /*
! 354: * Get the block numbers; we don't handle fragments
! 355: */
! 356: ap = ip->di_db;
! 357: for (i = 0; i < NDADDR && *ap && ndb; i++, ap++, ndb--) {
! 358: blk = fsbtodb(fs, *ap);
! 359: if (verbose)
! 360: printf("%d: %d\n", i, blk);
! 361: block_table[i] = blk;
! 362: }
! 363: if (ndb == 0)
! 364: return 0;
! 365:
! 366: /*
! 367: * Just one level of indirections; there isn't much room
! 368: * for more in the 1st-level bootblocks anyway.
! 369: */
! 370: blk = fsbtodb(fs, ip->di_ib[0]);
! 371: devread(devfd, buf, blk, fs->fs_bsize, "indirect block");
! 372: ap = (daddr_t *)buf;
! 373: for (; i < NINDIR(fs) && *ap && ndb; i++, ap++, ndb--) {
! 374: blk = fsbtodb(fs, *ap);
! 375: if (verbose)
! 376: printf("%d: %d\n", i, blk);
! 377: block_table[i] = blk;
! 378: }
! 379:
! 380: return 0;
! 381: }
! 382:
! 383: static void
! 384: vid_to_disklabel(char *dkname, char *bootproto)
! 385: {
! 386: char *specname;
! 387: int exe_file, f;
! 388: struct mvmedisklabel *pcpul;
! 389: struct stat stat;
! 390: unsigned int exe_addr;
! 391: unsigned short exe_addr_u;
! 392: unsigned short exe_addr_l;
! 393:
! 394: pcpul = (struct mvmedisklabel *)malloc(sizeof(struct mvmedisklabel));
! 395: bzero(pcpul, sizeof(struct mvmedisklabel));
! 396:
! 397: if (verbose)
! 398: printf("modifying vid.\n");
! 399:
! 400: exe_file = open(bootproto, O_RDONLY, 0444);
! 401: if (exe_file == -1) {
! 402: perror(bootproto);
! 403: exit(2);
! 404: }
! 405:
! 406: f = opendev(dkname, O_RDWR, OPENDEV_PART, &specname);
! 407:
! 408: if (lseek(f, 0, SEEK_SET) < 0 ||
! 409: read(f, pcpul, sizeof(struct mvmedisklabel)) <
! 410: sizeof(struct mvmedisklabel))
! 411: err(4, "%s", specname);
! 412:
! 413:
! 414: pcpul->version = 1;
! 415: strncpy(pcpul->vid_id, "M68K", 4);
! 416:
! 417: fstat(exe_file, &stat);
! 418:
! 419: /* size in 256 byte blocks round up after a.out header removed */
! 420:
! 421: pcpul->vid_oss = 2;
! 422: pcpul->vid_osl = (((stat.st_size -0x20) +511) / 512) *2;
! 423:
! 424: lseek(exe_file, 0x14, SEEK_SET);
! 425: read(exe_file, &exe_addr, 4);
! 426:
! 427: /* check this, it may not work in both endian. */
! 428: /* No, it doesn't. Use a big endian machine for now. SPM */
! 429:
! 430: {
! 431: union {
! 432: struct s {
! 433: unsigned short s1;
! 434: unsigned short s2;
! 435: } s;
! 436: unsigned long l;
! 437: } a;
! 438: a.l = exe_addr;
! 439: pcpul->vid_osa_u = a.s.s1;
! 440: pcpul->vid_osa_l = a.s.s2;
! 441:
! 442: }
! 443: pcpul->vid_cas = 1;
! 444: pcpul->vid_cal = 1;
! 445:
! 446: /* do not want to write past end of structure, not null terminated */
! 447:
! 448: strncpy(pcpul->vid_mot, "MOTOROLA", 8);
! 449:
! 450: pcpul->cfg_rec = 0x100;
! 451: pcpul->cfg_psm = 0x200;
! 452:
! 453: if (!nowrite) {
! 454: if (lseek(f, 0, SEEK_SET) < 0 ||
! 455: write(f, pcpul, sizeof(struct mvmedisklabel)) <
! 456: sizeof(struct mvmedisklabel))
! 457: err(4, "%s", specname);
! 458: }
! 459: free(pcpul);
! 460:
! 461: close(exe_file);
! 462: close(f);
! 463: }
CVSweb