xref: /netbsd-src/sys/arch/x68k/stand/boot_ufs/readufs_ffs.c (revision 10ad5ffa714ce1a679dcc9dd8159648df2d67b5a)
1 /*	$NetBSD: readufs_ffs.c,v 1.12 2009/03/18 10:22:38 cegger Exp $	*/
2 /*	from Id: readufs_ffs.c,v 1.6 2003/04/08 09:19:32 itohy Exp 	*/
3 
4 /*
5  * FS specific support for 4.2BSD Fast Filesystem
6  *
7  * Written in 1999, 2002, 2003 by ITOH Yasufumi (itohy@NetBSD.org).
8  * Public domain.
9  *
10  * Intended to be used for boot programs (first stage).
11  * DON'T ADD ANY FANCY FEATURE.  THIS SHALL BE COMPACT.
12  */
13 
14 #include "readufs.h"
15 
16 #include <ufs/ffs/fs.h>
17 
18 static int get_ffs_inode(ino32_t ino, union ufs_dinode *dibuf);
19 
20 #define fsi	(*ufsinfo)
21 #define fsi_ffs	fsi.fs_u.u_ffs
22 
23 /*
24  * Read and check superblock.
25  * If it is an FFS, save information from the superblock.
26  */
27 int
28 try_ffs(void)
29 {
30 	union {
31 		struct fs	sblk;
32 		unsigned char	pad[SBLOCKSIZE];
33 	} buf;
34 	struct ufs_info *ufsinfo = &ufs_info;
35 	static const int sblocs[] = SBLOCKSEARCH;
36 	const int *sbl;
37 	int magic;
38 
39 #ifdef DEBUG_WITH_STDIO
40 	printf("trying FFS\n");
41 #endif
42 	/* read FFS superblock */
43 	for (sbl = sblocs; ; sbl++) {
44 		if (*sbl == -1)
45 			return 1;
46 
47 		RAW_READ(&buf, (daddr_t) btodb(*sbl), SBLOCKSIZE);
48 
49 		magic = buf.sblk.fs_magic;
50 #ifdef DEBUG_WITH_STDIO
51 		printf("FFS: sblk: pos %d magic 0x%x\n", btodb(*sbl), magic);
52 #endif
53 #ifdef USE_UFS1
54 		if (magic == FS_UFS1_MAGIC
55 		    && !(buf.sblk.fs_old_flags & FS_FLAGS_UPDATED)) {
56 			if (*sbl == SBLOCK_UFS2)
57 				/* might be an alternate suberblock */
58 				continue;
59 			break;
60 		}
61 #endif
62 		if (*sbl != buf.sblk.fs_sblockloc)
63 			/* must be an alternate suberblock */
64 			continue;
65 
66 #ifdef USE_UFS1
67 		if (magic == FS_UFS1_MAGIC) {
68 			break;
69 		}
70 #endif
71 #ifdef USE_UFS2
72 		if (magic == FS_UFS2_MAGIC) {
73 #ifdef USE_UFS1
74 			fsi.ufstype = UFSTYPE_UFS2;
75 #endif
76 			break;
77 		}
78 #endif
79 	}
80 
81 	/*
82 	 * XXX <ufs/ffs/fs.h> always uses fs_magic
83 	 * (UFS1 only or UFS2 only is impossible)
84 	 */
85 	fsi_ffs.magic = magic;
86 #ifdef DEBUG_WITH_STDIO
87 	printf("FFS: detected UFS%d format\n", (magic == FS_UFS2_MAGIC) + 1);
88 #endif
89 
90 	/* This partition looks like an FFS. */
91 	fsi.fstype = UFSTYPE_FFS;
92 	fsi.get_inode = get_ffs_inode;
93 
94 	/* Get information from the superblock. */
95 	fsi.bsize = buf.sblk.fs_bsize;
96 	fsi.fsbtodb = buf.sblk.fs_fsbtodb;
97 	fsi.nindir = buf.sblk.fs_nindir;
98 
99 	fsi_ffs.iblkno = buf.sblk.fs_iblkno;
100 	fsi_ffs.old_cgoffset = buf.sblk.fs_old_cgoffset;
101 	fsi_ffs.old_cgmask = buf.sblk.fs_old_cgmask;
102 	fsi_ffs.fragshift = buf.sblk.fs_fragshift;
103 	fsi_ffs.inopb = buf.sblk.fs_inopb;
104 	fsi_ffs.ipg = buf.sblk.fs_ipg;
105 	fsi_ffs.fpg = buf.sblk.fs_fpg;
106 
107 	return 0;
108 }
109 
110 /* for inode macros */
111 #define fs_ipg		fs_u.u_ffs.ipg
112 #define fs_iblkno	fs_u.u_ffs.iblkno
113 #define fs_old_cgoffset	fs_u.u_ffs.old_cgoffset
114 #define fs_old_cgmask	fs_u.u_ffs.old_cgmask
115 #define fs_fpg		fs_u.u_ffs.fpg
116 #define fs_magic	fs_u.u_ffs.magic
117 #define fs_inopb	fs_u.u_ffs.inopb
118 #define fs_fragshift	fs_u.u_ffs.fragshift
119 #define fs_fsbtodb	fsbtodb
120 
121 /*
122  * Get inode from disk.
123  */
124 static int
125 get_ffs_inode(ino32_t ino, union ufs_dinode *dibuf)
126 {
127 	struct ufs_info *ufsinfo = &ufs_info;
128 	union ufs_dinode *buf = alloca((size_t) fsi.bsize);
129 	union ufs_dinode *di;
130 	unsigned ioff;
131 
132 	RAW_READ(buf, fsbtodb(&fsi, ino_to_fsba(&fsi, ino)),
133 			(size_t) fsi.bsize);
134 
135 	ioff = ino_to_fsbo(&fsi, ino);
136 
137 #if defined(USE_UFS1) && defined(USE_UFS2)
138 	if (ufsinfo->ufstype == UFSTYPE_UFS1)
139 		di = (void *) &(&buf->di1)[ioff];
140 	else {
141 		di = (void *) &(&buf->di2)[ioff];
142 
143 		/* XXX for DI_SIZE() macro */
144 		di->di1.di_size = di->di2.di_size;
145 	}
146 #else
147 	di = &buf[ioff];
148 #endif
149 
150 #ifdef DEBUG_WITH_STDIO
151 	printf("FFS: dinode(%d): mode 0%o, nlink %d, size %u\n",
152 		ino, di->di_common.di_mode, di->di_common.di_nlink,
153 		(unsigned) DI_SIZE(di));
154 #endif
155 
156 	if (di->di_common.di_mode == 0)
157 		return 1;	/* unused inode (file is not found) */
158 
159 	*dibuf = *di;
160 
161 	return 0;
162 }
163