xref: /openbsd/sys/arch/alpha/stand/installboot.c (revision 108bc87a)
1*108bc87aSotto /*	$OpenBSD: installboot.c,v 1.20 2020/03/11 09:59:31 otto Exp $	*/
2dfe00690Smillert /*	$NetBSD: installboot.c,v 1.2 1997/04/06 08:41:12 cgd Exp $	*/
334fbf6deSderaadt 
434fbf6deSderaadt /*
5dfe00690Smillert  * Copyright (c) 1997 Christopher G. Demetriou.  All rights reserved.
634fbf6deSderaadt  * Copyright (c) 1994 Paul Kranenburg
734fbf6deSderaadt  * All rights reserved.
834fbf6deSderaadt  *
934fbf6deSderaadt  * Redistribution and use in source and binary forms, with or without
1034fbf6deSderaadt  * modification, are permitted provided that the following conditions
1134fbf6deSderaadt  * are met:
1234fbf6deSderaadt  * 1. Redistributions of source code must retain the above copyright
1334fbf6deSderaadt  *    notice, this list of conditions and the following disclaimer.
1434fbf6deSderaadt  * 2. Redistributions in binary form must reproduce the above copyright
1534fbf6deSderaadt  *    notice, this list of conditions and the following disclaimer in the
1634fbf6deSderaadt  *    documentation and/or other materials provided with the distribution.
1734fbf6deSderaadt  * 3. All advertising materials mentioning features or use of this software
1834fbf6deSderaadt  *    must display the following acknowledgement:
1934fbf6deSderaadt  *      This product includes software developed by Paul Kranenburg.
2034fbf6deSderaadt  * 4. The name of the author may not be used to endorse or promote products
2134fbf6deSderaadt  *    derived from this software without specific prior written permission
2234fbf6deSderaadt  *
2334fbf6deSderaadt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2434fbf6deSderaadt  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2534fbf6deSderaadt  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2634fbf6deSderaadt  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2734fbf6deSderaadt  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2834fbf6deSderaadt  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2934fbf6deSderaadt  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3034fbf6deSderaadt  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3134fbf6deSderaadt  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3234fbf6deSderaadt  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3334fbf6deSderaadt  */
3434fbf6deSderaadt 
3534fbf6deSderaadt #include <sys/param.h>
3634fbf6deSderaadt #include <sys/mount.h>
37eafe1ee4Smillert #include <sys/ioctl.h>
3834fbf6deSderaadt #include <sys/time.h>
3934fbf6deSderaadt #include <sys/stat.h>
4034fbf6deSderaadt #include <sys/sysctl.h>
4134fbf6deSderaadt #include <ufs/ufs/dinode.h>
4234fbf6deSderaadt #include <ufs/ufs/dir.h>
4334fbf6deSderaadt #include <ufs/ffs/fs.h>
44dfe00690Smillert #include <sys/disklabel.h>
45dfe00690Smillert #include <sys/dkio.h>
4634fbf6deSderaadt #include <err.h>
47dfe00690Smillert #include <errno.h>
4834fbf6deSderaadt #include <fcntl.h>
4934fbf6deSderaadt #include <stdlib.h>
5034fbf6deSderaadt #include <stdio.h>
5134fbf6deSderaadt #include <string.h>
5234fbf6deSderaadt #include <unistd.h>
53dfe00690Smillert #include <util.h>
5434fbf6deSderaadt 
5534fbf6deSderaadt #include "bbinfo.h"
5634fbf6deSderaadt 
57eafe1ee4Smillert #ifndef	ISO_DEFAULT_BLOCK_SIZE
58eafe1ee4Smillert #define	ISO_DEFAULT_BLOCK_SIZE	2048
59eafe1ee4Smillert #endif
60eafe1ee4Smillert 
6134fbf6deSderaadt int	verbose, nowrite, hflag;
6234fbf6deSderaadt char	*boot, *proto, *dev;
6334fbf6deSderaadt 
6434fbf6deSderaadt struct bbinfoloc *bbinfolocp;
6534fbf6deSderaadt struct bbinfo *bbinfop;
6634fbf6deSderaadt int	max_block_count;
6734fbf6deSderaadt 
6834fbf6deSderaadt 
69c4071fd1Smillert char		*loadprotoblocks(char *, long *);
70c4071fd1Smillert int		loadblocknums(char *, int, unsigned long);
71*108bc87aSotto static void	devread(int, void *, daddr_t, size_t, char *);
72c4071fd1Smillert static void	usage(void);
73*108bc87aSotto static int	sbchk(struct fs *, daddr_t);
74*108bc87aSotto static void	sbread(int, daddr_t, struct fs **, char *);
75c4071fd1Smillert int		main(int, char *[]);
7634fbf6deSderaadt 
77eafe1ee4Smillert int	isofsblk = 0;
78eafe1ee4Smillert int	isofseblk = 0;
7934fbf6deSderaadt 
80*108bc87aSotto static const daddr_t sbtry[] = SBLOCKSEARCH;
81*108bc87aSotto 
8234fbf6deSderaadt static void
usage(void)8317262f28Sderaadt usage(void)
8434fbf6deSderaadt {
85dfe00690Smillert 	(void)fprintf(stderr,
86eafe1ee4Smillert 	    "usage: installboot [-n] [-v] [-s isofsblk -e isofseblk] "
87eafe1ee4Smillert 	    "<boot> <proto> <device>\n");
8834fbf6deSderaadt 	exit(1);
8934fbf6deSderaadt }
9034fbf6deSderaadt 
9134fbf6deSderaadt int
main(int argc,char * argv[])9217262f28Sderaadt main(int argc, char *argv[])
9334fbf6deSderaadt {
9417262f28Sderaadt 	int	c, devfd;
9534fbf6deSderaadt 	char	*protostore;
9634fbf6deSderaadt 	long	protosize;
97dfe00690Smillert 	struct stat disksb, bootsb;
98dfe00690Smillert 	struct disklabel dl;
991abdbfdeSderaadt 	daddr_t partoffset;
10017262f28Sderaadt #define BBPAD   0x1e0
10117262f28Sderaadt 	struct bb {
10217262f28Sderaadt 		char	bb_pad[BBPAD];	/* disklabel lives in here, actually */
10317262f28Sderaadt 		long	bb_secsize;	/* size of secondary boot block */
10417262f28Sderaadt 		long	bb_secstart;	/* start of secondary boot block */
10517262f28Sderaadt 		long	bb_flags;	/* unknown; always zero */
10617262f28Sderaadt 		long	bb_cksum;	/* checksum of the boot block, as longs. */
10717262f28Sderaadt 	} bb;
10817262f28Sderaadt 	long *lp, *ep;
10934fbf6deSderaadt 
110eafe1ee4Smillert 	while ((c = getopt(argc, argv, "vns:e:")) != -1) {
11134fbf6deSderaadt 		switch (c) {
11234fbf6deSderaadt 		case 'n':
11334fbf6deSderaadt 			/* Do not actually write the bootblock to disk */
11434fbf6deSderaadt 			nowrite = 1;
11534fbf6deSderaadt 			break;
11634fbf6deSderaadt 		case 'v':
11734fbf6deSderaadt 			/* Chat */
11834fbf6deSderaadt 			verbose = 1;
11934fbf6deSderaadt 			break;
120eafe1ee4Smillert 		case 's':
121eafe1ee4Smillert 			isofsblk = atoi(optarg);
122eafe1ee4Smillert 			break;
123eafe1ee4Smillert 		case 'e':
124eafe1ee4Smillert 			isofseblk = atoi(optarg);
125eafe1ee4Smillert 			break;
12634fbf6deSderaadt 		default:
12734fbf6deSderaadt 			usage();
12834fbf6deSderaadt 		}
12934fbf6deSderaadt 	}
13034fbf6deSderaadt 
131eafe1ee4Smillert 	if (argc - optind < 3)
13234fbf6deSderaadt 		usage();
13334fbf6deSderaadt 
13434fbf6deSderaadt 	boot = argv[optind];
13534fbf6deSderaadt 	proto = argv[optind + 1];
13634fbf6deSderaadt 	dev = argv[optind + 2];
13734fbf6deSderaadt 
13834fbf6deSderaadt 	if (verbose) {
139dfe00690Smillert 		(void)printf("boot: %s\n", boot);
140dfe00690Smillert 		(void)printf("proto: %s\n", proto);
141dfe00690Smillert 		(void)printf("device: %s\n", dev);
14234fbf6deSderaadt 	}
14334fbf6deSderaadt 
14434fbf6deSderaadt 	/* Load proto blocks into core */
14534fbf6deSderaadt 	if ((protostore = loadprotoblocks(proto, &protosize)) == NULL)
14634fbf6deSderaadt 		exit(1);
14734fbf6deSderaadt 
14834fbf6deSderaadt 	/* Open and check raw disk device */
1499eb7d26aSmillert 	if ((devfd = opendev(dev, O_RDONLY, OPENDEV_PART, &dev)) < 0)
15034fbf6deSderaadt 		err(1, "open: %s", dev);
151dfe00690Smillert 	if (fstat(devfd, &disksb) == -1)
152dfe00690Smillert 		err(1, "fstat: %s", dev);
153dfe00690Smillert 	if (!S_ISCHR(disksb.st_mode))
154dfe00690Smillert 		errx(1, "%s must be a character device node", dev);
155dfe00690Smillert 	if ((minor(disksb.st_rdev) % getmaxpartitions()) != getrawpartition())
156dfe00690Smillert 		errx(1, "%s must be the raw partition", dev);
15734fbf6deSderaadt 
15834fbf6deSderaadt 	/* Extract and load block numbers */
159dfe00690Smillert 	if (stat(boot, &bootsb) == -1)
160dfe00690Smillert 		err(1, "stat: %s", boot);
161dfe00690Smillert 	if (!S_ISREG(bootsb.st_mode))
162dfe00690Smillert 		errx(1, "%s must be a regular file", boot);
163dfe00690Smillert 	if ((minor(disksb.st_rdev) / getmaxpartitions()) !=
164dfe00690Smillert 	    (minor(bootsb.st_dev) / getmaxpartitions()))
165dfe00690Smillert 		errx(1, "%s must be somewhere on %s", boot, dev);
166dfe00690Smillert 
167dfe00690Smillert 	/*
168dfe00690Smillert 	 * Find the offset of the secondary boot block's partition
169dfe00690Smillert 	 * into the disk.  If disklabels not supported, assume zero.
170dfe00690Smillert 	 */
171dfe00690Smillert 	if (ioctl(devfd, DIOCGDINFO, &dl) != -1) {
17215aab03cSderaadt 		partoffset = DL_GETPOFFSET(&dl.d_partitions[minor(bootsb.st_dev) %
17315aab03cSderaadt 		    getmaxpartitions()]);
174dfe00690Smillert 	} else {
175dfe00690Smillert 		if (errno != ENOTTY)
176dfe00690Smillert 			err(1, "read disklabel: %s", dev);
177dfe00690Smillert 		warnx("couldn't read label from %s, using part offset of 0",
178dfe00690Smillert 		    dev);
179dfe00690Smillert 		partoffset = 0;
180dfe00690Smillert 	}
181dfe00690Smillert 	if (verbose)
1828234ed2eSjasper 		(void)printf("%s partition offset = 0x%llx\n", boot, partoffset);
183dfe00690Smillert 
184dfe00690Smillert 	/* Sync filesystems (make sure boot's block numbers are stable) */
185dfe00690Smillert 	sync();
186dfe00690Smillert 	sleep(2);
187dfe00690Smillert 	sync();
188dfe00690Smillert 	sleep(2);
189dfe00690Smillert 
190*108bc87aSotto 	if (loadblocknums(boot, devfd, DL_SECTOBLK(&dl, partoffset)) != 0)
19134fbf6deSderaadt 		exit(1);
19234fbf6deSderaadt 
19334fbf6deSderaadt 	(void)close(devfd);
19434fbf6deSderaadt 
19534fbf6deSderaadt 	if (nowrite)
19634fbf6deSderaadt 		return 0;
19734fbf6deSderaadt 
19834fbf6deSderaadt #if 0
19934fbf6deSderaadt 	/* Write patched proto bootblocks into the superblock */
20034fbf6deSderaadt 	if (protosize > SBSIZE - DEV_BSIZE)
20134fbf6deSderaadt 		errx(1, "proto bootblocks too big");
20234fbf6deSderaadt #endif
20334fbf6deSderaadt 
2049eb7d26aSmillert 	if ((devfd = opendev(dev, O_RDWR, OPENDEV_PART, &dev)) < 0)
20534fbf6deSderaadt 		err(1, "open: %s", dev);
20634fbf6deSderaadt 
20734fbf6deSderaadt 	if (lseek(devfd, DEV_BSIZE, SEEK_SET) != DEV_BSIZE)
20834fbf6deSderaadt 		err(1, "lseek bootstrap");
20934fbf6deSderaadt 
21034fbf6deSderaadt 	if (write(devfd, protostore, protosize) != protosize)
21134fbf6deSderaadt 		err(1, "write bootstrap");
21234fbf6deSderaadt 
21334fbf6deSderaadt 	if (lseek(devfd, 0, SEEK_SET) != 0)
21434fbf6deSderaadt 		err(1, "lseek label");
21534fbf6deSderaadt 
21634fbf6deSderaadt 	if (read(devfd, &bb, sizeof (bb)) != sizeof (bb))
21734fbf6deSderaadt 		err(1, "read label");
21834fbf6deSderaadt 
21934fbf6deSderaadt 	bb.bb_secsize = 15;
22034fbf6deSderaadt 	bb.bb_secstart = 1;
22134fbf6deSderaadt 	bb.bb_flags = 0;
22234fbf6deSderaadt 	bb.bb_cksum = 0;
22334fbf6deSderaadt 
22434fbf6deSderaadt 	for (lp = (long *)&bb, ep = &bb.bb_cksum; lp < ep; lp++)
22534fbf6deSderaadt 		bb.bb_cksum += *lp;
22634fbf6deSderaadt 
22734fbf6deSderaadt 	if (lseek(devfd, 0, SEEK_SET) != 0)
22834fbf6deSderaadt 		err(1, "lseek label 2");
22934fbf6deSderaadt 
23034fbf6deSderaadt 	if (write(devfd, &bb, sizeof bb) != sizeof bb)
23134fbf6deSderaadt 		err(1, "write label ");
23234fbf6deSderaadt 
23334fbf6deSderaadt 	(void)close(devfd);
23434fbf6deSderaadt 	return 0;
23534fbf6deSderaadt }
23634fbf6deSderaadt 
23734fbf6deSderaadt char *
loadprotoblocks(char * fname,long * size)23817262f28Sderaadt loadprotoblocks(char *fname, long *size)
23934fbf6deSderaadt {
24034fbf6deSderaadt 	int	fd, sz;
24134fbf6deSderaadt 	char	*bp;
24234fbf6deSderaadt 	struct	stat statbuf;
24334fbf6deSderaadt 	u_int64_t *matchp;
24434fbf6deSderaadt 
24534fbf6deSderaadt 	/*
24634fbf6deSderaadt 	 * Read the prototype boot block into memory.
24734fbf6deSderaadt 	 */
24834fbf6deSderaadt 	if ((fd = open(fname, O_RDONLY)) < 0) {
24934fbf6deSderaadt 		warn("open: %s", fname);
25034fbf6deSderaadt 		return NULL;
25134fbf6deSderaadt 	}
25234fbf6deSderaadt 	if (fstat(fd, &statbuf) != 0) {
25334fbf6deSderaadt 		warn("fstat: %s", fname);
25434fbf6deSderaadt 		close(fd);
25534fbf6deSderaadt 		return NULL;
25634fbf6deSderaadt 	}
25734fbf6deSderaadt 	sz = roundup(statbuf.st_size, DEV_BSIZE);
25834fbf6deSderaadt 	if ((bp = calloc(sz, 1)) == NULL) {
25934fbf6deSderaadt 		warnx("malloc: %s: no memory", fname);
26034fbf6deSderaadt 		close(fd);
26134fbf6deSderaadt 		return NULL;
26234fbf6deSderaadt 	}
26334fbf6deSderaadt 	if (read(fd, bp, statbuf.st_size) != statbuf.st_size) {
26434fbf6deSderaadt 		warn("read: %s", fname);
2654c67e3eeStedu 		free(bp);
26634fbf6deSderaadt 		close(fd);
26734fbf6deSderaadt 		return NULL;
26834fbf6deSderaadt 	}
26934fbf6deSderaadt 	close(fd);
27034fbf6deSderaadt 
27134fbf6deSderaadt 	/*
27234fbf6deSderaadt 	 * Find the magic area of the program, and figure out where
27334fbf6deSderaadt 	 * the 'blocks' struct is, from that.
27434fbf6deSderaadt 	 */
27534fbf6deSderaadt 	bbinfolocp = NULL;
27634fbf6deSderaadt 	for (matchp = (u_int64_t *)bp; (char *)matchp < bp + sz; matchp++) {
27734fbf6deSderaadt 		if (*matchp != 0xbabefacedeadbeef)
27834fbf6deSderaadt 			continue;
27934fbf6deSderaadt 		bbinfolocp = (struct bbinfoloc *)matchp;
28034fbf6deSderaadt 		if (bbinfolocp->magic1 == 0xbabefacedeadbeef &&
28134fbf6deSderaadt 		    bbinfolocp->magic2 == 0xdeadbeeffacebabe)
28234fbf6deSderaadt 			break;
28334fbf6deSderaadt 		bbinfolocp = NULL;
28434fbf6deSderaadt 	}
28534fbf6deSderaadt 
28634fbf6deSderaadt 	if (bbinfolocp == NULL) {
28734fbf6deSderaadt 		warnx("%s: not a valid boot block?", fname);
28834fbf6deSderaadt 		return NULL;
28934fbf6deSderaadt 	}
29034fbf6deSderaadt 
29134fbf6deSderaadt 	bbinfop = (struct bbinfo *)(bp + bbinfolocp->end - bbinfolocp->start);
29234fbf6deSderaadt 	memset(bbinfop, 0, sz - (bbinfolocp->end - bbinfolocp->start));
29334fbf6deSderaadt 	max_block_count =
29434fbf6deSderaadt 	    ((char *)bbinfop->blocks - bp) / sizeof (bbinfop->blocks[0]);
29534fbf6deSderaadt 
29634fbf6deSderaadt 	if (verbose) {
297dfe00690Smillert 		(void)printf("boot block info locator at offset 0x%x\n",
29834fbf6deSderaadt 			(char *)bbinfolocp - bp);
299dfe00690Smillert 		(void)printf("boot block info at offset 0x%x\n",
30034fbf6deSderaadt 			(char *)bbinfop - bp);
301dfe00690Smillert 		(void)printf("max number of blocks: %d\n", max_block_count);
30234fbf6deSderaadt 	}
30334fbf6deSderaadt 
30434fbf6deSderaadt 	*size = sz;
30534fbf6deSderaadt 	return (bp);
30634fbf6deSderaadt }
30734fbf6deSderaadt 
30834fbf6deSderaadt static void
devread(int fd,void * buf,daddr_t blk,size_t size,char * msg)309*108bc87aSotto devread(int fd, void *buf, daddr_t blk, size_t size, char *msg)
31034fbf6deSderaadt {
311*108bc87aSotto 	if (pread(fd, buf, size, dbtob((off_t)blk)) != (ssize_t)size)
312*108bc87aSotto 		err(1, "%s: devread: pread", msg);
31334fbf6deSderaadt }
31434fbf6deSderaadt 
31534fbf6deSderaadt static char sblock[SBSIZE];
31634fbf6deSderaadt 
31734fbf6deSderaadt int
loadblocknums(char * boot,int devfd,unsigned long partoffset)31817262f28Sderaadt loadblocknums(char *boot, int devfd, unsigned long partoffset)
31934fbf6deSderaadt {
32017262f28Sderaadt 	int		i, fd, ndb;
32134fbf6deSderaadt 	struct	stat	statbuf;
32234fbf6deSderaadt 	struct	statfs	statfsbuf;
32334fbf6deSderaadt 	struct fs	*fs;
32434fbf6deSderaadt 	char		*buf;
325*108bc87aSotto 	daddr32_t	*ap1;
326*108bc87aSotto 	daddr_t		blk, *ap2;
327*108bc87aSotto 	struct ufs1_dinode	*ip1;
328*108bc87aSotto 	struct ufs2_dinode	*ip2;
32934fbf6deSderaadt 	int32_t		cksum;
33034fbf6deSderaadt 
33134fbf6deSderaadt 	/*
33234fbf6deSderaadt 	 * Open 2nd-level boot program and record the block numbers
33334fbf6deSderaadt 	 * it occupies on the filesystem represented by `devfd'.
33434fbf6deSderaadt 	 */
33534fbf6deSderaadt 	if ((fd = open(boot, O_RDONLY)) < 0)
33634fbf6deSderaadt 		err(1, "open: %s", boot);
33734fbf6deSderaadt 
33834fbf6deSderaadt 	if (fstatfs(fd, &statfsbuf) != 0)
33934fbf6deSderaadt 		err(1, "statfs: %s", boot);
34034fbf6deSderaadt 
341eafe1ee4Smillert 	if (isofsblk) {
342eafe1ee4Smillert 		bbinfop->bsize = ISO_DEFAULT_BLOCK_SIZE;
343eafe1ee4Smillert 		bbinfop->nblocks = isofseblk - isofsblk + 1;
344eafe1ee4Smillert 		if (bbinfop->nblocks > max_block_count)
345eafe1ee4Smillert 			errx(1, "%s: Too many blocks", boot);
346eafe1ee4Smillert 		if (verbose)
347eafe1ee4Smillert 			(void)printf("%s: starting block %d (%d total):\n\t",
348eafe1ee4Smillert 			    boot, isofsblk, bbinfop->nblocks);
349eafe1ee4Smillert 		for (i = 0; i < bbinfop->nblocks; i++) {
350eafe1ee4Smillert 			blk = (isofsblk + i) * (bbinfop->bsize / DEV_BSIZE);
351eafe1ee4Smillert 			bbinfop->blocks[i] = blk;
352eafe1ee4Smillert 			if (verbose)
353eafe1ee4Smillert 				(void)printf("%d ", blk);
354eafe1ee4Smillert 		}
355eafe1ee4Smillert 		if (verbose)
356eafe1ee4Smillert 			(void)printf("\n");
357eafe1ee4Smillert 
358eafe1ee4Smillert 		cksum = 0;
359eafe1ee4Smillert 		for (i = 0; i < bbinfop->nblocks +
360eafe1ee4Smillert 		    (sizeof(*bbinfop) / sizeof(bbinfop->blocks[0])) - 1; i++)
361eafe1ee4Smillert 			cksum += ((int32_t *)bbinfop)[i];
362eafe1ee4Smillert 		bbinfop->cksum = -cksum;
363eafe1ee4Smillert 
364eafe1ee4Smillert 		return 0;
365eafe1ee4Smillert 	}
366eafe1ee4Smillert 
36720399b6fSderaadt 	if (strncmp(statfsbuf.f_fstypename, MOUNT_FFS, MFSNAMELEN))
36820399b6fSderaadt 		errx(1, "%s: must be on a FFS filesystem", boot);
36934fbf6deSderaadt 
37034fbf6deSderaadt 	if (fsync(fd) != 0)
37134fbf6deSderaadt 		err(1, "fsync: %s", boot);
37234fbf6deSderaadt 
37334fbf6deSderaadt 	if (fstat(fd, &statbuf) != 0)
37434fbf6deSderaadt 		err(1, "fstat: %s", boot);
37534fbf6deSderaadt 
37634fbf6deSderaadt 	close(fd);
37734fbf6deSderaadt 
37834fbf6deSderaadt 	/* Read superblock */
379*108bc87aSotto 	sbread(devfd, partoffset, &fs, sblock);
38034fbf6deSderaadt 
38134fbf6deSderaadt 	/* Read inode */
38234fbf6deSderaadt 	if ((buf = malloc(fs->fs_bsize)) == NULL)
38334fbf6deSderaadt 		errx(1, "No memory for filesystem block");
38434fbf6deSderaadt 
38534fbf6deSderaadt 	blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));
386dfe00690Smillert 	devread(devfd, buf, blk + partoffset, fs->fs_bsize, "inode");
387*108bc87aSotto 	if (fs->fs_magic == FS_UFS1_MAGIC) {
388*108bc87aSotto 		ip1 = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs,
389*108bc87aSotto 		    statbuf.st_ino);
390*108bc87aSotto 		ndb = howmany(ip1->di_size, fs->fs_bsize);
391*108bc87aSotto 	} else {
392*108bc87aSotto 		ip2 = (struct ufs2_dinode *)(buf) + ino_to_fsbo(fs,
393*108bc87aSotto 		    statbuf.st_ino);
394*108bc87aSotto 		ndb = howmany(ip2->di_size, fs->fs_bsize);
395*108bc87aSotto 	}
396*108bc87aSotto 	/*
397*108bc87aSotto 	 * Check the block numbers; we don't handle fragments
398*108bc87aSotto 	 */
399*108bc87aSotto 	if (ndb > max_block_count)
400*108bc87aSotto 		errx(1, "%s: Too many blocks", boot);
40134fbf6deSderaadt 
40234fbf6deSderaadt 	/*
40334fbf6deSderaadt 	 * Register filesystem block size.
40434fbf6deSderaadt 	 */
40534fbf6deSderaadt 	bbinfop->bsize = fs->fs_bsize;
40634fbf6deSderaadt 
40734fbf6deSderaadt 	/*
40834fbf6deSderaadt 	 * Register block count.
40934fbf6deSderaadt 	 */
41034fbf6deSderaadt 	bbinfop->nblocks = ndb;
41134fbf6deSderaadt 
41234fbf6deSderaadt 	if (verbose)
413dfe00690Smillert 		(void)printf("%s: block numbers: ", boot);
414*108bc87aSotto 	if (fs->fs_magic == FS_UFS1_MAGIC) {
415*108bc87aSotto 		ap1 = ip1->di_db;
416*108bc87aSotto 		for (i = 0; i < NDADDR && *ap1 && ndb; i++, ap1++, ndb--) {
417*108bc87aSotto 			blk = fsbtodb(fs, *ap1);
418dfe00690Smillert 			bbinfop->blocks[i] = blk + partoffset;
41934fbf6deSderaadt 			if (verbose)
420dfe00690Smillert 				(void)printf("%d ", bbinfop->blocks[i]);
42134fbf6deSderaadt 		}
422*108bc87aSotto 	} else {
423*108bc87aSotto 		ap2 = ip2->di_db;
424*108bc87aSotto 		for (i = 0; i < NDADDR && *ap2 && ndb; i++, ap2++, ndb--) {
425*108bc87aSotto 			blk = fsbtodb(fs, *ap2);
426*108bc87aSotto 			bbinfop->blocks[i] = blk + partoffset;
427*108bc87aSotto 			if (verbose)
428*108bc87aSotto 				(void)printf("%d ", bbinfop->blocks[i]);
429*108bc87aSotto 		}
430*108bc87aSotto 	}
43134fbf6deSderaadt 	if (verbose)
432dfe00690Smillert 		(void)printf("\n");
43334fbf6deSderaadt 
43434fbf6deSderaadt 	if (ndb == 0)
43534fbf6deSderaadt 		goto checksum;
43634fbf6deSderaadt 
43734fbf6deSderaadt 	/*
43834fbf6deSderaadt 	 * Just one level of indirections; there isn't much room
43934fbf6deSderaadt 	 * for more in the 1st-level bootblocks anyway.
44034fbf6deSderaadt 	 */
44134fbf6deSderaadt 	if (verbose)
442dfe00690Smillert 		(void)printf("%s: block numbers (indirect): ", boot);
443*108bc87aSotto 	if (fs->fs_magic == FS_UFS1_MAGIC) {
444*108bc87aSotto 		blk = ip1->di_ib[0];
445dfe00690Smillert 		devread(devfd, buf, blk + partoffset, fs->fs_bsize,
446dfe00690Smillert 		    "indirect block");
447*108bc87aSotto 		ap1 = (daddr32_t *)buf;
448*108bc87aSotto 		for (; i < NINDIR(fs) && *ap1 && ndb; i++, ap1++, ndb--) {
449*108bc87aSotto 			blk = fsbtodb(fs, *ap1);
450dfe00690Smillert 			bbinfop->blocks[i] = blk + partoffset;
45134fbf6deSderaadt 			if (verbose)
452dfe00690Smillert 				(void)printf("%d ", bbinfop->blocks[i]);
45334fbf6deSderaadt 		}
454*108bc87aSotto 	} else {
455*108bc87aSotto 		blk = ip2->di_ib[0];
456*108bc87aSotto 		devread(devfd, buf, blk + partoffset, fs->fs_bsize,
457*108bc87aSotto 		    "indirect block");
458*108bc87aSotto 		ap2 = (daddr_t *)buf;
459*108bc87aSotto 		for (; i < NINDIR(fs) && *ap2 && ndb; i++, ap2++, ndb--) {
460*108bc87aSotto 			blk = fsbtodb(fs, *ap2);
461*108bc87aSotto 			bbinfop->blocks[i] = blk + partoffset;
462*108bc87aSotto 			if (verbose)
463*108bc87aSotto 				(void)printf("%d ", bbinfop->blocks[i]);
464*108bc87aSotto 		}
465*108bc87aSotto 	}
46634fbf6deSderaadt 	if (verbose)
467dfe00690Smillert 		(void)printf("\n");
46834fbf6deSderaadt 
46934fbf6deSderaadt 	if (ndb)
47034fbf6deSderaadt 		errx(1, "%s: Too many blocks", boot);
47134fbf6deSderaadt 
47234fbf6deSderaadt checksum:
47334fbf6deSderaadt 	cksum = 0;
47434fbf6deSderaadt 	for (i = 0; i < bbinfop->nblocks +
47517262f28Sderaadt 	    (sizeof (*bbinfop) / sizeof (bbinfop->blocks[0])) - 1; i++)
47634fbf6deSderaadt 		cksum += ((int32_t *)bbinfop)[i];
47734fbf6deSderaadt 	bbinfop->cksum = -cksum;
47834fbf6deSderaadt 
47934fbf6deSderaadt 	return 0;
48034fbf6deSderaadt }
481*108bc87aSotto 
482*108bc87aSotto static int
sbchk(struct fs * fs,daddr_t sbloc)483*108bc87aSotto sbchk(struct fs *fs, daddr_t sbloc)
484*108bc87aSotto {
485*108bc87aSotto 	if (verbose)
486*108bc87aSotto 		fprintf(stderr, "looking for superblock at %lld\n", sbloc);
487*108bc87aSotto 
488*108bc87aSotto 	if (fs->fs_magic != FS_UFS2_MAGIC && fs->fs_magic != FS_UFS1_MAGIC) {
489*108bc87aSotto 		if (verbose)
490*108bc87aSotto 			fprintf(stderr, "bad superblock magic 0x%x\n",
491*108bc87aSotto 			    fs->fs_magic);
492*108bc87aSotto 		return (0);
493*108bc87aSotto 	}
494*108bc87aSotto 
495*108bc87aSotto 	/*
496*108bc87aSotto 	 * Looking for an FFS1 file system at SBLOCK_UFS2 will find the
497*108bc87aSotto 	 * wrong superblock for file systems with 64k block size.
498*108bc87aSotto 	 */
499*108bc87aSotto 	if (fs->fs_magic == FS_UFS1_MAGIC && sbloc == SBLOCK_UFS2) {
500*108bc87aSotto 		if (verbose)
501*108bc87aSotto 			fprintf(stderr, "skipping ffs1 superblock at %lld\n",
502*108bc87aSotto 			    sbloc);
503*108bc87aSotto 		return (0);
504*108bc87aSotto 	}
505*108bc87aSotto 
506*108bc87aSotto 	if (fs->fs_bsize <= 0 || fs->fs_bsize < sizeof(struct fs) ||
507*108bc87aSotto 	    fs->fs_bsize > MAXBSIZE) {
508*108bc87aSotto 		if (verbose)
509*108bc87aSotto 			fprintf(stderr, "invalid superblock block size %d\n",
510*108bc87aSotto 			    fs->fs_bsize);
511*108bc87aSotto 		return (0);
512*108bc87aSotto 	}
513*108bc87aSotto 
514*108bc87aSotto 	if (fs->fs_sbsize <= 0 || fs->fs_sbsize > SBSIZE) {
515*108bc87aSotto 		if (verbose)
516*108bc87aSotto 			fprintf(stderr, "invalid superblock size %d\n",
517*108bc87aSotto 			    fs->fs_sbsize);
518*108bc87aSotto 		return (0);
519*108bc87aSotto 	}
520*108bc87aSotto 
521*108bc87aSotto 	if (fs->fs_inopb <= 0) {
522*108bc87aSotto 		if (verbose)
523*108bc87aSotto 			fprintf(stderr, "invalid superblock inodes/block %d\n",
524*108bc87aSotto 			    fs->fs_inopb);
525*108bc87aSotto 		return (0);
526*108bc87aSotto 	}
527*108bc87aSotto 
528*108bc87aSotto 	if (verbose)
529*108bc87aSotto 		fprintf(stderr, "found valid %s superblock\n",
530*108bc87aSotto 		    fs->fs_magic == FS_UFS2_MAGIC ? "ffs2" : "ffs1");
531*108bc87aSotto 
532*108bc87aSotto 	return (1);
533*108bc87aSotto }
534*108bc87aSotto 
535*108bc87aSotto static void
sbread(int fd,daddr_t poffset,struct fs ** fs,char * sblock)536*108bc87aSotto sbread(int fd, daddr_t poffset, struct fs **fs, char *sblock)
537*108bc87aSotto {
538*108bc87aSotto 	int i;
539*108bc87aSotto 	daddr_t sboff;
540*108bc87aSotto 
541*108bc87aSotto 	for (i = 0; sbtry[i] != -1; i++) {
542*108bc87aSotto 		sboff = sbtry[i] / DEV_BSIZE;
543*108bc87aSotto 		devread(fd, sblock, poffset + sboff, SBSIZE, "superblock");
544*108bc87aSotto 		*fs = (struct fs *)sblock;
545*108bc87aSotto 		if (sbchk(*fs, sbtry[i]))
546*108bc87aSotto 			break;
547*108bc87aSotto 	}
548*108bc87aSotto 
549*108bc87aSotto 	if (sbtry[i] == -1)
550*108bc87aSotto 		errx(1, "couldn't find ffs superblock");
551*108bc87aSotto }
552