1*87ba0e2aSchs /* $NetBSD: ffs.c,v 1.33 2022/11/17 06:40:40 chs Exp $ */
28eb8919eSlukem
38eb8919eSlukem /*-
48eb8919eSlukem * Copyright (c) 2002 The NetBSD Foundation, Inc.
58eb8919eSlukem * All rights reserved.
68eb8919eSlukem *
78eb8919eSlukem * This code is derived from software contributed to The NetBSD Foundation
88eb8919eSlukem * by Matt Fredette.
98eb8919eSlukem *
108eb8919eSlukem * Redistribution and use in source and binary forms, with or without
118eb8919eSlukem * modification, are permitted provided that the following conditions
128eb8919eSlukem * are met:
138eb8919eSlukem * 1. Redistributions of source code must retain the above copyright
148eb8919eSlukem * notice, this list of conditions and the following disclaimer.
158eb8919eSlukem * 2. Redistributions in binary form must reproduce the above copyright
168eb8919eSlukem * notice, this list of conditions and the following disclaimer in the
178eb8919eSlukem * documentation and/or other materials provided with the distribution.
188eb8919eSlukem *
198eb8919eSlukem * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
208eb8919eSlukem * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
218eb8919eSlukem * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
228eb8919eSlukem * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
238eb8919eSlukem * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
248eb8919eSlukem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
258eb8919eSlukem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
268eb8919eSlukem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
278eb8919eSlukem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
288eb8919eSlukem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
298eb8919eSlukem * POSSIBILITY OF SUCH DAMAGE.
308eb8919eSlukem */
318eb8919eSlukem
32b2f78261Sjmc #if HAVE_NBTOOL_CONFIG_H
33b2f78261Sjmc #include "nbtool_config.h"
34b2f78261Sjmc #endif
35b2f78261Sjmc
368eb8919eSlukem #include <sys/cdefs.h>
37e5f39b5eStsutsui #if !defined(__lint)
38*87ba0e2aSchs __RCSID("$NetBSD: ffs.c,v 1.33 2022/11/17 06:40:40 chs Exp $");
398eb8919eSlukem #endif /* !__lint */
408eb8919eSlukem
418eb8919eSlukem #include <sys/param.h>
42b2f78261Sjmc
43b2f78261Sjmc #if !HAVE_NBTOOL_CONFIG_H
448eb8919eSlukem #include <sys/mount.h>
45b2f78261Sjmc #endif
468eb8919eSlukem
478eb8919eSlukem #include <assert.h>
488eb8919eSlukem #include <err.h>
498eb8919eSlukem #include <errno.h>
508eb8919eSlukem #include <fcntl.h>
518eb8919eSlukem #include <stdarg.h>
528eb8919eSlukem #include <stdio.h>
538eb8919eSlukem #include <stdlib.h>
548eb8919eSlukem #include <string.h>
558eb8919eSlukem #include <unistd.h>
568eb8919eSlukem
578eb8919eSlukem #include "installboot.h"
588eb8919eSlukem
59f00029f8Sjdc /* From <dev/raidframe/raidframevar.h> */
60f00029f8Sjdc #define RF_PROTECTED_SECTORS 64L
61373c7523Sjdc
628eb8919eSlukem #undef DIRBLKSIZ
638eb8919eSlukem
648eb8919eSlukem #include <ufs/ufs/dinode.h>
658eb8919eSlukem #include <ufs/ufs/dir.h>
668eb8919eSlukem #include <ufs/ffs/fs.h>
678eb8919eSlukem #include <ufs/ffs/ffs_extern.h>
688c767ff5Sdsl #ifndef NO_FFS_SWAP
698eb8919eSlukem #include <ufs/ufs/ufs_bswap.h>
708c767ff5Sdsl #else
718c767ff5Sdsl #define ffs_sb_swap(fs_a, fs_b)
728c767ff5Sdsl #define ffs_dinode1_swap(inode_a, inode_b)
738c767ff5Sdsl #define ffs_dinode2_swap(inode_a, inode_b)
748c767ff5Sdsl #endif
758eb8919eSlukem
76373c7523Sjdc static int ffs_match_common(ib_params *, off_t);
77d1a5b782Schristos static int ffs_read_disk_block(ib_params *, uint64_t, int, char []);
7842614ed3Sfvdl static int ffs_find_disk_blocks_ufs1(ib_params *, ino_t,
7942614ed3Sfvdl int (*)(ib_params *, void *, uint64_t, uint32_t), void *);
8042614ed3Sfvdl static int ffs_find_disk_blocks_ufs2(ib_params *, ino_t,
8142614ed3Sfvdl int (*)(ib_params *, void *, uint64_t, uint32_t), void *);
8242614ed3Sfvdl static int ffs_findstage2_ino(ib_params *, void *, uint64_t, uint32_t);
8342614ed3Sfvdl static int ffs_findstage2_blocks(ib_params *, void *, uint64_t, uint32_t);
8442614ed3Sfvdl
8542614ed3Sfvdl static int is_ufs2;
861bdd92eeSlukem
871bdd92eeSlukem
888eb8919eSlukem /* This reads a disk block from the filesystem. */
898eb8919eSlukem static int
ffs_read_disk_block(ib_params * params,uint64_t blkno,int size,char blk[])90d1a5b782Schristos ffs_read_disk_block(ib_params *params, uint64_t blkno, int size, char blk[])
918eb8919eSlukem {
928eb8919eSlukem int rv;
938eb8919eSlukem
941a478e40Slukem assert(params != NULL);
958eb8919eSlukem assert(params->filesystem != NULL);
968eb8919eSlukem assert(params->fsfd != -1);
978eb8919eSlukem assert(size > 0);
988eb8919eSlukem assert(blk != NULL);
998eb8919eSlukem
10017ad8eceStsutsui rv = pread(params->fsfd, blk, size, blkno * params->sectorsize);
1018eb8919eSlukem if (rv == -1) {
102ad1f16e9She warn("Reading block %llu in `%s'",
103ad1f16e9She (unsigned long long)blkno, params->filesystem);
1048eb8919eSlukem return (0);
1058eb8919eSlukem } else if (rv != size) {
106ad1f16e9She warnx("Reading block %llu in `%s': short read",
107ad1f16e9She (unsigned long long)blkno, params->filesystem);
1088eb8919eSlukem return (0);
1098eb8919eSlukem }
1108eb8919eSlukem
1118eb8919eSlukem return (1);
1128eb8919eSlukem }
1138eb8919eSlukem
1148eb8919eSlukem /*
1158eb8919eSlukem * This iterates over the data blocks belonging to an inode,
1168eb8919eSlukem * making a callback each iteration with the disk block number
1178eb8919eSlukem * and the size.
1188eb8919eSlukem */
1198eb8919eSlukem static int
ffs_find_disk_blocks_ufs1(ib_params * params,ino_t ino,int (* callback)(ib_params *,void *,uint64_t,uint32_t),void * state)12042614ed3Sfvdl ffs_find_disk_blocks_ufs1(ib_params *params, ino_t ino,
12142614ed3Sfvdl int (*callback)(ib_params *, void *, uint64_t, uint32_t),
1228eb8919eSlukem void *state)
1238eb8919eSlukem {
12442614ed3Sfvdl char sbbuf[SBLOCKSIZE];
1258eb8919eSlukem struct fs *fs;
1268eb8919eSlukem char inodebuf[MAXBSIZE];
12742614ed3Sfvdl struct ufs1_dinode *inode;
1288eb8919eSlukem int level_i;
12942614ed3Sfvdl int32_t blk, lblk, nblk;
1308eb8919eSlukem int rv;
1318eb8919eSlukem #define LEVELS 4
1328eb8919eSlukem struct {
133a3ff3a30Sfvdl int32_t *blknums;
1348eb8919eSlukem unsigned long blkcount;
1358eb8919eSlukem char diskbuf[MAXBSIZE];
1368eb8919eSlukem } level[LEVELS];
1378eb8919eSlukem
1381a478e40Slukem assert(params != NULL);
1391bdd92eeSlukem assert(params->fstype != NULL);
1401a478e40Slukem assert(callback != NULL);
1411a478e40Slukem assert(state != NULL);
1421a478e40Slukem
1438eb8919eSlukem /* Read the superblock. */
144798d0c81She if (!ffs_read_disk_block(params, params->fstype->sblockloc, SBLOCKSIZE,
14542614ed3Sfvdl sbbuf))
1468eb8919eSlukem return (0);
1478eb8919eSlukem fs = (struct fs *)sbbuf;
1482f5213daShe #ifndef NO_FFS_SWAP
1491bdd92eeSlukem if (params->fstype->needswap)
1508eb8919eSlukem ffs_sb_swap(fs, fs);
1512f5213daShe #endif
1528eb8919eSlukem
1538eb8919eSlukem if (fs->fs_inopb <= 0) {
1548eb8919eSlukem warnx("Bad inopb %d in superblock in `%s'",
1558eb8919eSlukem fs->fs_inopb, params->filesystem);
1568eb8919eSlukem return (0);
1578eb8919eSlukem }
1588eb8919eSlukem
1598eb8919eSlukem /* Read the inode. */
160373c7523Sjdc if (! ffs_read_disk_block(params,
1612737439dSdholland FFS_FSBTODB(fs, ino_to_fsba(fs, ino)) + params->fstype->offset,
1628eb8919eSlukem fs->fs_bsize, inodebuf))
1638eb8919eSlukem return (0);
16442614ed3Sfvdl inode = (struct ufs1_dinode *)inodebuf;
1658eb8919eSlukem inode += ino_to_fsbo(fs, ino);
1662f5213daShe #ifndef NO_FFS_SWAP
1671bdd92eeSlukem if (params->fstype->needswap)
16842614ed3Sfvdl ffs_dinode1_swap(inode, inode);
1692f5213daShe #endif
1708eb8919eSlukem
1718eb8919eSlukem /* Get the block count and initialize for our block walk. */
1728eb8919eSlukem nblk = howmany(inode->di_size, fs->fs_bsize);
1738eb8919eSlukem lblk = 0;
1748eb8919eSlukem level_i = 0;
1758eb8919eSlukem level[0].blknums = &inode->di_db[0];
176dcd34a91Sdholland level[0].blkcount = UFS_NDADDR;
1778eb8919eSlukem level[1].blknums = &inode->di_ib[0];
1788eb8919eSlukem level[1].blkcount = 1;
1798eb8919eSlukem level[2].blknums = &inode->di_ib[1];
1808eb8919eSlukem level[2].blkcount = 1;
1818eb8919eSlukem level[3].blknums = &inode->di_ib[2];
1828eb8919eSlukem level[3].blkcount = 1;
1838eb8919eSlukem
1848eb8919eSlukem /* Walk the data blocks. */
1858eb8919eSlukem while (nblk > 0) {
1868eb8919eSlukem
1878eb8919eSlukem /*
1888eb8919eSlukem * If there are no more blocks at this indirection
1898eb8919eSlukem * level, move up one indirection level and loop.
1908eb8919eSlukem */
1918eb8919eSlukem if (level[level_i].blkcount == 0) {
1928eb8919eSlukem if (++level_i == LEVELS)
1938eb8919eSlukem break;
1948eb8919eSlukem continue;
1958eb8919eSlukem }
1968eb8919eSlukem
1978eb8919eSlukem /* Get the next block at this level. */
1988eb8919eSlukem blk = *(level[level_i].blknums++);
1998eb8919eSlukem level[level_i].blkcount--;
2001bdd92eeSlukem if (params->fstype->needswap)
2018eb8919eSlukem blk = bswap32(blk);
2028eb8919eSlukem
2038eb8919eSlukem #if 0
2048eb8919eSlukem fprintf(stderr, "ino %lu blk %lu level %d\n", ino, blk,
2058eb8919eSlukem level_i);
2068eb8919eSlukem #endif
2078eb8919eSlukem
2088eb8919eSlukem /*
2098eb8919eSlukem * If we're not at the direct level, descend one
2108eb8919eSlukem * level, read in that level's new block list,
2118eb8919eSlukem * and loop.
2128eb8919eSlukem */
2138eb8919eSlukem if (level_i > 0) {
2148eb8919eSlukem level_i--;
2158eb8919eSlukem if (blk == 0)
2168eb8919eSlukem memset(level[level_i].diskbuf, 0, MAXBSIZE);
2178eb8919eSlukem else if (! ffs_read_disk_block(params,
2182737439dSdholland FFS_FSBTODB(fs, blk) + params->fstype->offset,
2198eb8919eSlukem fs->fs_bsize, level[level_i].diskbuf))
2208eb8919eSlukem return (0);
221a3ff3a30Sfvdl /* XXX ondisk32 */
2228eb8919eSlukem level[level_i].blknums =
223a3ff3a30Sfvdl (int32_t *)level[level_i].diskbuf;
224f1333577Sdholland level[level_i].blkcount = FFS_NINDIR(fs);
2258eb8919eSlukem continue;
2268eb8919eSlukem }
2278eb8919eSlukem
2288eb8919eSlukem /* blk is the next direct level block. */
2298eb8919eSlukem #if 0
2308eb8919eSlukem fprintf(stderr, "ino %lu db %lu blksize %lu\n", ino,
2312737439dSdholland FFS_FSBTODB(fs, blk), ffs_sblksize(fs, inode->di_size, lblk));
2328eb8919eSlukem #endif
2338eb8919eSlukem rv = (*callback)(params, state,
2342737439dSdholland FFS_FSBTODB(fs, blk) + params->fstype->offset,
235f1333577Sdholland ffs_sblksize(fs, (int64_t)inode->di_size, lblk));
23642614ed3Sfvdl lblk++;
23742614ed3Sfvdl nblk--;
23842614ed3Sfvdl if (rv != 1)
23942614ed3Sfvdl return (rv);
24042614ed3Sfvdl }
24142614ed3Sfvdl
24242614ed3Sfvdl if (nblk != 0) {
243c4ee9f6dSchristos warnx("Inode %llu in `%s' ran out of blocks?",
244c4ee9f6dSchristos (unsigned long long)ino, params->filesystem);
24542614ed3Sfvdl return (0);
24642614ed3Sfvdl }
24742614ed3Sfvdl
24842614ed3Sfvdl return (1);
24942614ed3Sfvdl }
25042614ed3Sfvdl
25142614ed3Sfvdl /*
25242614ed3Sfvdl * This iterates over the data blocks belonging to an inode,
25342614ed3Sfvdl * making a callback each iteration with the disk block number
25442614ed3Sfvdl * and the size.
25542614ed3Sfvdl */
25642614ed3Sfvdl static int
ffs_find_disk_blocks_ufs2(ib_params * params,ino_t ino,int (* callback)(ib_params *,void *,uint64_t,uint32_t),void * state)25742614ed3Sfvdl ffs_find_disk_blocks_ufs2(ib_params *params, ino_t ino,
25842614ed3Sfvdl int (*callback)(ib_params *, void *, uint64_t, uint32_t),
25942614ed3Sfvdl void *state)
26042614ed3Sfvdl {
26142614ed3Sfvdl char sbbuf[SBLOCKSIZE];
26242614ed3Sfvdl struct fs *fs;
26342614ed3Sfvdl char inodebuf[MAXBSIZE];
26442614ed3Sfvdl struct ufs2_dinode *inode;
26542614ed3Sfvdl int level_i;
26642614ed3Sfvdl int64_t blk, lblk, nblk;
26742614ed3Sfvdl int rv;
26842614ed3Sfvdl #define LEVELS 4
26942614ed3Sfvdl struct {
27042614ed3Sfvdl int64_t *blknums;
27142614ed3Sfvdl unsigned long blkcount;
27242614ed3Sfvdl char diskbuf[MAXBSIZE];
27342614ed3Sfvdl } level[LEVELS];
27442614ed3Sfvdl
27542614ed3Sfvdl assert(params != NULL);
27642614ed3Sfvdl assert(params->fstype != NULL);
27742614ed3Sfvdl assert(callback != NULL);
27842614ed3Sfvdl assert(state != NULL);
27942614ed3Sfvdl
28042614ed3Sfvdl /* Read the superblock. */
281798d0c81She if (!ffs_read_disk_block(params, params->fstype->sblockloc, SBLOCKSIZE,
28242614ed3Sfvdl sbbuf))
28342614ed3Sfvdl return (0);
28442614ed3Sfvdl fs = (struct fs *)sbbuf;
2852f5213daShe #ifndef NO_FFS_SWAP
28642614ed3Sfvdl if (params->fstype->needswap)
28742614ed3Sfvdl ffs_sb_swap(fs, fs);
2882f5213daShe #endif
28942614ed3Sfvdl
29042614ed3Sfvdl if (fs->fs_inopb <= 0) {
29142614ed3Sfvdl warnx("Bad inopb %d in superblock in `%s'",
29242614ed3Sfvdl fs->fs_inopb, params->filesystem);
29342614ed3Sfvdl return (0);
29442614ed3Sfvdl }
29542614ed3Sfvdl
29642614ed3Sfvdl /* Read the inode. */
2974f0a5e98Sbad if (! ffs_read_disk_block(params,
2982737439dSdholland FFS_FSBTODB(fs, ino_to_fsba(fs, ino)) + params->fstype->offset,
29942614ed3Sfvdl fs->fs_bsize, inodebuf))
30042614ed3Sfvdl return (0);
30142614ed3Sfvdl inode = (struct ufs2_dinode *)inodebuf;
30242614ed3Sfvdl inode += ino_to_fsbo(fs, ino);
3032f5213daShe #ifndef NO_FFS_SWAP
30442614ed3Sfvdl if (params->fstype->needswap)
30542614ed3Sfvdl ffs_dinode2_swap(inode, inode);
3062f5213daShe #endif
30742614ed3Sfvdl
30842614ed3Sfvdl /* Get the block count and initialize for our block walk. */
30942614ed3Sfvdl nblk = howmany(inode->di_size, fs->fs_bsize);
31042614ed3Sfvdl lblk = 0;
31142614ed3Sfvdl level_i = 0;
31242614ed3Sfvdl level[0].blknums = &inode->di_db[0];
313dcd34a91Sdholland level[0].blkcount = UFS_NDADDR;
31442614ed3Sfvdl level[1].blknums = &inode->di_ib[0];
31542614ed3Sfvdl level[1].blkcount = 1;
31642614ed3Sfvdl level[2].blknums = &inode->di_ib[1];
31742614ed3Sfvdl level[2].blkcount = 1;
31842614ed3Sfvdl level[3].blknums = &inode->di_ib[2];
31942614ed3Sfvdl level[3].blkcount = 1;
32042614ed3Sfvdl
32142614ed3Sfvdl /* Walk the data blocks. */
32242614ed3Sfvdl while (nblk > 0) {
32342614ed3Sfvdl
32442614ed3Sfvdl /*
32542614ed3Sfvdl * If there are no more blocks at this indirection
32642614ed3Sfvdl * level, move up one indirection level and loop.
32742614ed3Sfvdl */
32842614ed3Sfvdl if (level[level_i].blkcount == 0) {
32942614ed3Sfvdl if (++level_i == LEVELS)
33042614ed3Sfvdl break;
33142614ed3Sfvdl continue;
33242614ed3Sfvdl }
33342614ed3Sfvdl
33442614ed3Sfvdl /* Get the next block at this level. */
33542614ed3Sfvdl blk = *(level[level_i].blknums++);
33642614ed3Sfvdl level[level_i].blkcount--;
33742614ed3Sfvdl if (params->fstype->needswap)
33842614ed3Sfvdl blk = bswap64(blk);
33942614ed3Sfvdl
34042614ed3Sfvdl #if 0
34142614ed3Sfvdl fprintf(stderr, "ino %lu blk %llu level %d\n", ino,
34242614ed3Sfvdl (unsigned long long)blk, level_i);
34342614ed3Sfvdl #endif
34442614ed3Sfvdl
34542614ed3Sfvdl /*
34642614ed3Sfvdl * If we're not at the direct level, descend one
34742614ed3Sfvdl * level, read in that level's new block list,
34842614ed3Sfvdl * and loop.
34942614ed3Sfvdl */
35042614ed3Sfvdl if (level_i > 0) {
35142614ed3Sfvdl level_i--;
35242614ed3Sfvdl if (blk == 0)
35342614ed3Sfvdl memset(level[level_i].diskbuf, 0, MAXBSIZE);
35442614ed3Sfvdl else if (! ffs_read_disk_block(params,
3552737439dSdholland FFS_FSBTODB(fs, blk) + params->fstype->offset,
35642614ed3Sfvdl fs->fs_bsize, level[level_i].diskbuf))
35742614ed3Sfvdl return (0);
35842614ed3Sfvdl level[level_i].blknums =
35942614ed3Sfvdl (int64_t *)level[level_i].diskbuf;
360f1333577Sdholland level[level_i].blkcount = FFS_NINDIR(fs);
36142614ed3Sfvdl continue;
36242614ed3Sfvdl }
36342614ed3Sfvdl
36442614ed3Sfvdl /* blk is the next direct level block. */
36542614ed3Sfvdl #if 0
36642614ed3Sfvdl fprintf(stderr, "ino %lu db %llu blksize %lu\n", ino,
3672737439dSdholland FFS_FSBTODB(fs, blk), ffs_sblksize(fs, inode->di_size, lblk));
36842614ed3Sfvdl #endif
36942614ed3Sfvdl rv = (*callback)(params, state,
3702737439dSdholland FFS_FSBTODB(fs, blk) + params->fstype->offset,
371f1333577Sdholland ffs_sblksize(fs, (int64_t)inode->di_size, lblk));
3728eb8919eSlukem lblk++;
3738eb8919eSlukem nblk--;
3748eb8919eSlukem if (rv != 1)
3758eb8919eSlukem return (rv);
3768eb8919eSlukem }
3778eb8919eSlukem
3788eb8919eSlukem if (nblk != 0) {
379c4ee9f6dSchristos warnx("Inode %llu in `%s' ran out of blocks?",
380c4ee9f6dSchristos (unsigned long long)ino, params->filesystem);
3818eb8919eSlukem return (0);
3828eb8919eSlukem }
3838eb8919eSlukem
3848eb8919eSlukem return (1);
3858eb8919eSlukem }
3868eb8919eSlukem
3878eb8919eSlukem /*
3888eb8919eSlukem * This callback reads a block of the root directory,
3898eb8919eSlukem * searches for an entry for the secondary bootstrap,
3908eb8919eSlukem * and saves the inode number if one is found.
3918eb8919eSlukem */
3928eb8919eSlukem static int
ffs_findstage2_ino(ib_params * params,void * _ino,uint64_t blk,uint32_t blksize)3938eb8919eSlukem ffs_findstage2_ino(ib_params *params, void *_ino,
39442614ed3Sfvdl uint64_t blk, uint32_t blksize)
3958eb8919eSlukem {
3968eb8919eSlukem char dirbuf[MAXBSIZE];
3978eb8919eSlukem struct direct *de, *ede;
3988eb8919eSlukem uint32_t ino;
3998eb8919eSlukem
4001a478e40Slukem assert(params != NULL);
4011bdd92eeSlukem assert(params->fstype != NULL);
402033fe17bSlukem assert(params->stage2 != NULL);
4031a478e40Slukem assert(_ino != NULL);
4041a478e40Slukem
4058eb8919eSlukem /* Skip directory holes. */
4068eb8919eSlukem if (blk == 0)
4078eb8919eSlukem return (1);
4088eb8919eSlukem
4098eb8919eSlukem /* Read the directory block. */
4108eb8919eSlukem if (! ffs_read_disk_block(params, blk, blksize, dirbuf))
4118eb8919eSlukem return (0);
4128eb8919eSlukem
4138eb8919eSlukem /* Loop over the directory entries. */
4148eb8919eSlukem de = (struct direct *)&dirbuf[0];
4158eb8919eSlukem ede = (struct direct *)&dirbuf[blksize];
4168eb8919eSlukem while (de < ede) {
417327a5715Sthorpej ino = de->d_fileno;
4181bdd92eeSlukem if (params->fstype->needswap) {
4198eb8919eSlukem ino = bswap32(ino);
4208eb8919eSlukem de->d_reclen = bswap16(de->d_reclen);
4218eb8919eSlukem }
4228eb8919eSlukem if (ino != 0 && strcmp(de->d_name, params->stage2) == 0) {
4238eb8919eSlukem *((uint32_t *)_ino) = ino;
4248eb8919eSlukem return (2);
4258eb8919eSlukem }
426a4a641e5Spk if (de->d_reclen == 0)
427a4a641e5Spk break;
4288eb8919eSlukem de = (struct direct *)((char *)de + de->d_reclen);
4298eb8919eSlukem }
4308eb8919eSlukem
4318eb8919eSlukem return (1);
4328eb8919eSlukem }
4338eb8919eSlukem
4348eb8919eSlukem struct findblks_state {
4358eb8919eSlukem uint32_t maxblk;
4368eb8919eSlukem uint32_t nblk;
4378eb8919eSlukem ib_block *blocks;
4388eb8919eSlukem };
4398eb8919eSlukem
4408eb8919eSlukem /* This callback records the blocks of the secondary bootstrap. */
4418eb8919eSlukem static int
ffs_findstage2_blocks(ib_params * params,void * _state,uint64_t blk,uint32_t blksize)4428eb8919eSlukem ffs_findstage2_blocks(ib_params *params, void *_state,
44342614ed3Sfvdl uint64_t blk, uint32_t blksize)
4448eb8919eSlukem {
4458eb8919eSlukem struct findblks_state *state = _state;
4468eb8919eSlukem
4471a478e40Slukem assert(params != NULL);
448033fe17bSlukem assert(params->stage2 != NULL);
4491a478e40Slukem assert(_state != NULL);
4501a478e40Slukem
4518eb8919eSlukem if (state->nblk == state->maxblk) {
452966b42a3Slukem warnx("Secondary bootstrap `%s' has too many blocks (max %d)",
453966b42a3Slukem params->stage2, state->maxblk);
4548eb8919eSlukem return (0);
4558eb8919eSlukem }
4568eb8919eSlukem state->blocks[state->nblk].block = blk;
4578eb8919eSlukem state->blocks[state->nblk].blocksize = blksize;
4588eb8919eSlukem state->nblk++;
4598eb8919eSlukem return (1);
4608eb8919eSlukem }
4618eb8919eSlukem
4621bdd92eeSlukem /*
463b5589158Slukem * publicly visible functions
4641bdd92eeSlukem */
4658eb8919eSlukem
46642614ed3Sfvdl static off_t sblock_try[] = SBLOCKSEARCH;
46742614ed3Sfvdl
4688eb8919eSlukem int
ffs_match(ib_params * params)4698eb8919eSlukem ffs_match(ib_params *params)
4708eb8919eSlukem {
471373c7523Sjdc return ffs_match_common(params, (off_t) 0);
472373c7523Sjdc }
473373c7523Sjdc
474373c7523Sjdc int
raid_match(ib_params * params)475373c7523Sjdc raid_match(ib_params *params)
476373c7523Sjdc {
477373c7523Sjdc /* XXX Assumes 512 bytes / sector */
47817ad8eceStsutsui if (params->sectorsize != 512) {
479373c7523Sjdc warnx("Media is %d bytes/sector."
480373c7523Sjdc " RAID is only supported on 512 bytes/sector media.",
48117ad8eceStsutsui params->sectorsize);
482373c7523Sjdc return 0;
483373c7523Sjdc }
484373c7523Sjdc return ffs_match_common(params, (off_t) RF_PROTECTED_SECTORS);
485373c7523Sjdc }
486373c7523Sjdc
487373c7523Sjdc int
ffs_match_common(ib_params * params,off_t offset)488373c7523Sjdc ffs_match_common(ib_params *params, off_t offset)
489373c7523Sjdc {
49042614ed3Sfvdl char sbbuf[SBLOCKSIZE];
4918eb8919eSlukem struct fs *fs;
49242614ed3Sfvdl int i;
49342614ed3Sfvdl off_t loc;
4948eb8919eSlukem
4951a478e40Slukem assert(params != NULL);
4961bdd92eeSlukem assert(params->fstype != NULL);
4971a478e40Slukem
4988eb8919eSlukem fs = (struct fs *)sbbuf;
49942614ed3Sfvdl for (i = 0; sblock_try[i] != -1; i++) {
50017ad8eceStsutsui loc = sblock_try[i] / params->sectorsize + offset;
50142614ed3Sfvdl if (!ffs_read_disk_block(params, loc, SBLOCKSIZE, sbbuf))
50242614ed3Sfvdl continue;
50342614ed3Sfvdl switch (fs->fs_magic) {
50442614ed3Sfvdl case FS_UFS2_MAGIC:
505*87ba0e2aSchs case FS_UFS2EA_MAGIC:
50642614ed3Sfvdl is_ufs2 = 1;
50742614ed3Sfvdl /* FALLTHROUGH */
50842614ed3Sfvdl case FS_UFS1_MAGIC:
5091bdd92eeSlukem params->fstype->needswap = 0;
5101bdd92eeSlukem params->fstype->blocksize = fs->fs_bsize;
51142614ed3Sfvdl params->fstype->sblockloc = loc;
512373c7523Sjdc params->fstype->offset = offset;
51343d718b9Sdsl break;
5148c767ff5Sdsl #ifndef FFS_NO_SWAP
51542614ed3Sfvdl case FS_UFS2_MAGIC_SWAPPED:
516*87ba0e2aSchs case FS_UFS2EA_MAGIC_SWAPPED:
51742614ed3Sfvdl is_ufs2 = 1;
51842614ed3Sfvdl /* FALLTHROUGH */
51942614ed3Sfvdl case FS_UFS1_MAGIC_SWAPPED:
5201bdd92eeSlukem params->fstype->needswap = 1;
5211bdd92eeSlukem params->fstype->blocksize = bswap32(fs->fs_bsize);
52242614ed3Sfvdl params->fstype->sblockloc = loc;
523373c7523Sjdc params->fstype->offset = offset;
52443d718b9Sdsl break;
5258c767ff5Sdsl #endif
52642614ed3Sfvdl default:
52742614ed3Sfvdl continue;
52842614ed3Sfvdl }
52943d718b9Sdsl if (!is_ufs2 && sblock_try[i] == SBLOCK_UFS2)
53043d718b9Sdsl continue;
53143d718b9Sdsl return 1;
5328eb8919eSlukem }
5338eb8919eSlukem
53442614ed3Sfvdl return (0);
5351bdd92eeSlukem }
5361bdd92eeSlukem
5378eb8919eSlukem int
ffs_findstage2(ib_params * params,uint32_t * maxblk,ib_block * blocks)5388eb8919eSlukem ffs_findstage2(ib_params *params, uint32_t *maxblk, ib_block *blocks)
5398eb8919eSlukem {
5408eb8919eSlukem int rv;
5418eb8919eSlukem uint32_t ino;
5428eb8919eSlukem struct findblks_state state;
5438eb8919eSlukem
5441a478e40Slukem assert(params != NULL);
5458eb8919eSlukem assert(params->stage2 != NULL);
5461a478e40Slukem assert(maxblk != NULL);
5471a478e40Slukem assert(blocks != NULL);
5488eb8919eSlukem
5491bdd92eeSlukem if (params->flags & IB_STAGE2START)
5501bdd92eeSlukem return (hardcode_stage2(params, maxblk, blocks));
5511bdd92eeSlukem
5528eb8919eSlukem /* The secondary bootstrap must be clearly in /. */
5538eb8919eSlukem if (params->stage2[0] == '/')
5548eb8919eSlukem params->stage2++;
5558eb8919eSlukem if (strchr(params->stage2, '/') != NULL) {
5568eb8919eSlukem warnx("The secondary bootstrap `%s' must be in /",
5578eb8919eSlukem params->stage2);
558984db960Sapb warnx("(Path must be relative to the file system in `%s')",
559984db960Sapb params->filesystem);
5608eb8919eSlukem return (0);
5618eb8919eSlukem }
5628eb8919eSlukem
5638eb8919eSlukem /* Get the inode number of the secondary bootstrap. */
56442614ed3Sfvdl if (is_ufs2)
565dcd34a91Sdholland rv = ffs_find_disk_blocks_ufs2(params, UFS_ROOTINO,
56642614ed3Sfvdl ffs_findstage2_ino, &ino);
56742614ed3Sfvdl else
568dcd34a91Sdholland rv = ffs_find_disk_blocks_ufs1(params, UFS_ROOTINO,
56942614ed3Sfvdl ffs_findstage2_ino, &ino);
570966b42a3Slukem if (rv != 2) {
571966b42a3Slukem warnx("Could not find secondary bootstrap `%s' in `%s'",
572966b42a3Slukem params->stage2, params->filesystem);
573984db960Sapb warnx("(Path must be relative to the file system in `%s')",
574984db960Sapb params->filesystem);
5758eb8919eSlukem return (0);
576966b42a3Slukem }
5778eb8919eSlukem
5788eb8919eSlukem /* Record the disk blocks of the secondary bootstrap. */
5798eb8919eSlukem state.maxblk = *maxblk;
5808eb8919eSlukem state.nblk = 0;
5818eb8919eSlukem state.blocks = blocks;
58242614ed3Sfvdl if (is_ufs2)
58342614ed3Sfvdl rv = ffs_find_disk_blocks_ufs2(params, ino,
58442614ed3Sfvdl ffs_findstage2_blocks, &state);
585eb9a70f8Sdsl else
58642614ed3Sfvdl rv = ffs_find_disk_blocks_ufs1(params, ino,
58742614ed3Sfvdl ffs_findstage2_blocks, &state);
588966b42a3Slukem if (! rv) {
5898eb8919eSlukem return (0);
590966b42a3Slukem }
5918eb8919eSlukem
5928eb8919eSlukem *maxblk = state.nblk;
5938eb8919eSlukem return (1);
5948eb8919eSlukem }
595