Annotation of sys/arch/alpha/stand/installboot.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: installboot.c,v 1.14 2007/06/06 17:15:11 deraadt Exp $ */
2: /* $NetBSD: installboot.c,v 1.2 1997/04/06 08:41:12 cgd Exp $ */
3:
4: /*
5: * Copyright (c) 1997 Christopher G. Demetriou. All rights reserved.
6: * Copyright (c) 1994 Paul Kranenburg
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Paul Kranenburg.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: */
34:
35: #include <sys/param.h>
36: #include <sys/mount.h>
37: #include <sys/ioctl.h>
38: #include <sys/time.h>
39: #include <sys/stat.h>
40: #include <sys/sysctl.h>
41: #include <ufs/ufs/dinode.h>
42: #include <ufs/ufs/dir.h>
43: #include <ufs/ffs/fs.h>
44: #include <sys/disklabel.h>
45: #include <sys/dkio.h>
46: #include <err.h>
47: #include <errno.h>
48: #include <fcntl.h>
49: #include <stdlib.h>
50: #include <stdio.h>
51: #include <string.h>
52: #include <unistd.h>
53: #include <util.h>
54:
55: #include "bbinfo.h"
56:
57: #ifndef ISO_DEFAULT_BLOCK_SIZE
58: #define ISO_DEFAULT_BLOCK_SIZE 2048
59: #endif
60:
61: int verbose, nowrite, hflag;
62: char *boot, *proto, *dev;
63:
64: struct bbinfoloc *bbinfolocp;
65: struct bbinfo *bbinfop;
66: int max_block_count;
67:
68:
69: char *loadprotoblocks(char *, long *);
70: int loadblocknums(char *, int, unsigned long);
71: static void devread(int, void *, daddr_t, size_t, char *);
72: static void usage(void);
73: int main(int, char *[]);
74:
75: int isofsblk = 0;
76: int isofseblk = 0;
77:
78: static void
79: usage(void)
80: {
81: (void)fprintf(stderr,
82: "usage: installboot [-n] [-v] [-s isofsblk -e isofseblk] "
83: "<boot> <proto> <device>\n");
84: exit(1);
85: }
86:
87: int
88: main(int argc, char *argv[])
89: {
90: int c, devfd;
91: char *protostore;
92: long protosize;
93: struct stat disksb, bootsb;
94: struct disklabel dl;
95: daddr64_t partoffset;
96: #define BBPAD 0x1e0
97: struct bb {
98: char bb_pad[BBPAD]; /* disklabel lives in here, actually */
99: long bb_secsize; /* size of secondary boot block */
100: long bb_secstart; /* start of secondary boot block */
101: long bb_flags; /* unknown; always zero */
102: long bb_cksum; /* checksum of the boot block, as longs. */
103: } bb;
104: long *lp, *ep;
105:
106: while ((c = getopt(argc, argv, "vns:e:")) != -1) {
107: switch (c) {
108: case 'n':
109: /* Do not actually write the bootblock to disk */
110: nowrite = 1;
111: break;
112: case 'v':
113: /* Chat */
114: verbose = 1;
115: break;
116: case 's':
117: isofsblk = atoi(optarg);
118: break;
119: case 'e':
120: isofseblk = atoi(optarg);
121: break;
122: default:
123: usage();
124: }
125: }
126:
127: if (argc - optind < 3)
128: usage();
129:
130: boot = argv[optind];
131: proto = argv[optind + 1];
132: dev = argv[optind + 2];
133:
134: if (verbose) {
135: (void)printf("boot: %s\n", boot);
136: (void)printf("proto: %s\n", proto);
137: (void)printf("device: %s\n", dev);
138: }
139:
140: /* Load proto blocks into core */
141: if ((protostore = loadprotoblocks(proto, &protosize)) == NULL)
142: exit(1);
143:
144: /* Open and check raw disk device */
145: if ((devfd = opendev(dev, O_RDONLY, OPENDEV_PART, &dev)) < 0)
146: err(1, "open: %s", dev);
147: if (fstat(devfd, &disksb) == -1)
148: err(1, "fstat: %s", dev);
149: if (!S_ISCHR(disksb.st_mode))
150: errx(1, "%s must be a character device node", dev);
151: if ((minor(disksb.st_rdev) % getmaxpartitions()) != getrawpartition())
152: errx(1, "%s must be the raw partition", dev);
153:
154: /* Extract and load block numbers */
155: if (stat(boot, &bootsb) == -1)
156: err(1, "stat: %s", boot);
157: if (!S_ISREG(bootsb.st_mode))
158: errx(1, "%s must be a regular file", boot);
159: if ((minor(disksb.st_rdev) / getmaxpartitions()) !=
160: (minor(bootsb.st_dev) / getmaxpartitions()))
161: errx(1, "%s must be somewhere on %s", boot, dev);
162:
163: /*
164: * Find the offset of the secondary boot block's partition
165: * into the disk. If disklabels not supported, assume zero.
166: */
167: if (ioctl(devfd, DIOCGDINFO, &dl) != -1) {
168: partoffset = DL_GETPOFFSET(&dl.d_partitions[minor(bootsb.st_dev) %
169: getmaxpartitions()]);
170: } else {
171: if (errno != ENOTTY)
172: err(1, "read disklabel: %s", dev);
173: warnx("couldn't read label from %s, using part offset of 0",
174: dev);
175: partoffset = 0;
176: }
177: if (verbose)
178: (void)printf("%s partition offset = 0x%lx\n", boot, partoffset);
179:
180: /* Sync filesystems (make sure boot's block numbers are stable) */
181: sync();
182: sleep(2);
183: sync();
184: sleep(2);
185:
186: if (loadblocknums(boot, devfd, partoffset) != 0)
187: exit(1);
188:
189: (void)close(devfd);
190:
191: if (nowrite)
192: return 0;
193:
194: #if 0
195: /* Write patched proto bootblocks into the superblock */
196: if (protosize > SBSIZE - DEV_BSIZE)
197: errx(1, "proto bootblocks too big");
198: #endif
199:
200: if ((devfd = opendev(dev, O_RDWR, OPENDEV_PART, &dev)) < 0)
201: err(1, "open: %s", dev);
202:
203: if (lseek(devfd, DEV_BSIZE, SEEK_SET) != DEV_BSIZE)
204: err(1, "lseek bootstrap");
205:
206: if (write(devfd, protostore, protosize) != protosize)
207: err(1, "write bootstrap");
208:
209: if (lseek(devfd, 0, SEEK_SET) != 0)
210: err(1, "lseek label");
211:
212: if (read(devfd, &bb, sizeof (bb)) != sizeof (bb))
213: err(1, "read label");
214:
215: bb.bb_secsize = 15;
216: bb.bb_secstart = 1;
217: bb.bb_flags = 0;
218: bb.bb_cksum = 0;
219:
220: for (lp = (long *)&bb, ep = &bb.bb_cksum; lp < ep; lp++)
221: bb.bb_cksum += *lp;
222:
223: if (lseek(devfd, 0, SEEK_SET) != 0)
224: err(1, "lseek label 2");
225:
226: if (write(devfd, &bb, sizeof bb) != sizeof bb)
227: err(1, "write label ");
228:
229: (void)close(devfd);
230: return 0;
231: }
232:
233: char *
234: loadprotoblocks(char *fname, long *size)
235: {
236: int fd, sz;
237: char *bp;
238: struct stat statbuf;
239: u_int64_t *matchp;
240:
241: /*
242: * Read the prototype boot block into memory.
243: */
244: if ((fd = open(fname, O_RDONLY)) < 0) {
245: warn("open: %s", fname);
246: return NULL;
247: }
248: if (fstat(fd, &statbuf) != 0) {
249: warn("fstat: %s", fname);
250: close(fd);
251: return NULL;
252: }
253: sz = roundup(statbuf.st_size, DEV_BSIZE);
254: if ((bp = calloc(sz, 1)) == NULL) {
255: warnx("malloc: %s: no memory", fname);
256: close(fd);
257: return NULL;
258: }
259: if (read(fd, bp, statbuf.st_size) != statbuf.st_size) {
260: warn("read: %s", fname);
261: free(bp);
262: close(fd);
263: return NULL;
264: }
265: close(fd);
266:
267: /*
268: * Find the magic area of the program, and figure out where
269: * the 'blocks' struct is, from that.
270: */
271: bbinfolocp = NULL;
272: for (matchp = (u_int64_t *)bp; (char *)matchp < bp + sz; matchp++) {
273: if (*matchp != 0xbabefacedeadbeef)
274: continue;
275: bbinfolocp = (struct bbinfoloc *)matchp;
276: if (bbinfolocp->magic1 == 0xbabefacedeadbeef &&
277: bbinfolocp->magic2 == 0xdeadbeeffacebabe)
278: break;
279: bbinfolocp = NULL;
280: }
281:
282: if (bbinfolocp == NULL) {
283: warnx("%s: not a valid boot block?", fname);
284: return NULL;
285: }
286:
287: bbinfop = (struct bbinfo *)(bp + bbinfolocp->end - bbinfolocp->start);
288: memset(bbinfop, 0, sz - (bbinfolocp->end - bbinfolocp->start));
289: max_block_count =
290: ((char *)bbinfop->blocks - bp) / sizeof (bbinfop->blocks[0]);
291:
292: if (verbose) {
293: (void)printf("boot block info locator at offset 0x%x\n",
294: (char *)bbinfolocp - bp);
295: (void)printf("boot block info at offset 0x%x\n",
296: (char *)bbinfop - bp);
297: (void)printf("max number of blocks: %d\n", max_block_count);
298: }
299:
300: *size = sz;
301: return (bp);
302: }
303:
304: static void
305: devread(int fd, void *buf, daddr_t blk, size_t size, char *msg)
306: {
307: if (lseek(fd, dbtob(blk), SEEK_SET) != dbtob(blk))
308: err(1, "%s: devread: lseek", msg);
309:
310: if (read(fd, buf, size) != size)
311: err(1, "%s: devread: read", msg);
312: }
313:
314: static char sblock[SBSIZE];
315:
316: int
317: loadblocknums(char *boot, int devfd, unsigned long partoffset)
318: {
319: int i, fd, ndb;
320: struct stat statbuf;
321: struct statfs statfsbuf;
322: struct fs *fs;
323: char *buf;
324: daddr_t blk, *ap;
325: struct ufs1_dinode *ip;
326: int32_t cksum;
327:
328: /*
329: * Open 2nd-level boot program and record the block numbers
330: * it occupies on the filesystem represented by `devfd'.
331: */
332: if ((fd = open(boot, O_RDONLY)) < 0)
333: err(1, "open: %s", boot);
334:
335: if (fstatfs(fd, &statfsbuf) != 0)
336: err(1, "statfs: %s", boot);
337:
338: if (isofsblk) {
339: bbinfop->bsize = ISO_DEFAULT_BLOCK_SIZE;
340: bbinfop->nblocks = isofseblk - isofsblk + 1;
341: if (bbinfop->nblocks > max_block_count)
342: errx(1, "%s: Too many blocks", boot);
343: if (verbose)
344: (void)printf("%s: starting block %d (%d total):\n\t",
345: boot, isofsblk, bbinfop->nblocks);
346: for (i = 0; i < bbinfop->nblocks; i++) {
347: blk = (isofsblk + i) * (bbinfop->bsize / DEV_BSIZE);
348: bbinfop->blocks[i] = blk;
349: if (verbose)
350: (void)printf("%d ", blk);
351: }
352: if (verbose)
353: (void)printf("\n");
354:
355: cksum = 0;
356: for (i = 0; i < bbinfop->nblocks +
357: (sizeof(*bbinfop) / sizeof(bbinfop->blocks[0])) - 1; i++)
358: cksum += ((int32_t *)bbinfop)[i];
359: bbinfop->cksum = -cksum;
360:
361: return 0;
362: }
363:
364: if (strncmp(statfsbuf.f_fstypename, MOUNT_FFS, MFSNAMELEN))
365: errx(1, "%s: must be on a FFS filesystem", boot);
366:
367: if (fsync(fd) != 0)
368: err(1, "fsync: %s", boot);
369:
370: if (fstat(fd, &statbuf) != 0)
371: err(1, "fstat: %s", boot);
372:
373: close(fd);
374:
375: /* Read superblock */
376: devread(devfd, sblock, btodb(SBOFF) + partoffset, SBSIZE,
377: "superblock");
378: fs = (struct fs *)sblock;
379:
380: /* Read inode */
381: if ((buf = malloc(fs->fs_bsize)) == NULL)
382: errx(1, "No memory for filesystem block");
383:
384: blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));
385: devread(devfd, buf, blk + partoffset, fs->fs_bsize, "inode");
386: ip = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino);
387:
388: /*
389: * Register filesystem block size.
390: */
391: bbinfop->bsize = fs->fs_bsize;
392:
393: /*
394: * Get the block numbers; we don't handle fragments
395: */
396: ndb = howmany(ip->di_size, fs->fs_bsize);
397: if (ndb > max_block_count)
398: errx(1, "%s: Too many blocks", boot);
399:
400: /*
401: * Register block count.
402: */
403: bbinfop->nblocks = ndb;
404:
405: if (verbose)
406: (void)printf("%s: block numbers: ", boot);
407: ap = ip->di_db;
408: for (i = 0; i < NDADDR && *ap && ndb; i++, ap++, ndb--) {
409: blk = fsbtodb(fs, *ap);
410: bbinfop->blocks[i] = blk + partoffset;
411: if (verbose)
412: (void)printf("%d ", bbinfop->blocks[i]);
413: }
414: if (verbose)
415: (void)printf("\n");
416:
417: if (ndb == 0)
418: goto checksum;
419:
420: /*
421: * Just one level of indirections; there isn't much room
422: * for more in the 1st-level bootblocks anyway.
423: */
424: if (verbose)
425: (void)printf("%s: block numbers (indirect): ", boot);
426: blk = ip->di_ib[0];
427: devread(devfd, buf, blk + partoffset, fs->fs_bsize,
428: "indirect block");
429: ap = (daddr_t *)buf;
430: for (; i < NINDIR(fs) && *ap && ndb; i++, ap++, ndb--) {
431: blk = fsbtodb(fs, *ap);
432: bbinfop->blocks[i] = blk + partoffset;
433: if (verbose)
434: (void)printf("%d ", bbinfop->blocks[i]);
435: }
436: if (verbose)
437: (void)printf("\n");
438:
439: if (ndb)
440: errx(1, "%s: Too many blocks", boot);
441:
442: checksum:
443: cksum = 0;
444: for (i = 0; i < bbinfop->nblocks +
445: (sizeof (*bbinfop) / sizeof (bbinfop->blocks[0])) - 1; i++)
446: cksum += ((int32_t *)bbinfop)[i];
447: bbinfop->cksum = -cksum;
448:
449: return 0;
450: }
CVSweb