Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / x68k / stand / boot_ufs / readufs.c
blobaac9bbb379e97c7729fb74f89606b01380e72405
1 /* $NetBSD: readufs.c,v 1.12 2009/03/14 21:04:17 dsl Exp $ */
2 /* from Id: readufs.c,v 1.8 2003/04/08 09:19:32 itohy Exp */
4 /*
5 * Read UFS (FFS / LFS)
7 * Written in 1999, 2002, 2003 by ITOH Yasufumi (itohy@NetBSD.org).
8 * Public domain.
10 * Intended to be used for boot programs (first stage).
11 * DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT.
14 #include "readufs.h"
16 #define fs ufs_info
18 static void raw_read_queue(void *buf, daddr_t blkpos, size_t bytelen);
19 static int ufs_read_indirect(daddr_t blk, int level, uint8_t **buf,
20 unsigned *poff, size_t count);
22 #ifdef DEBUG_WITH_STDIO
23 void ufs_list_dir(ino32_t dirino);
24 int main(int argc, char *argv[]);
25 #endif
27 #ifdef DEBUG_WITH_STDIO
28 int fd;
30 void
31 RAW_READ(void *buf, daddr_t blkpos, size_t bytelen)
34 if (pread(fd, buf, bytelen, (off_t)dbtob(blkpos)) != (ssize_t) bytelen)
35 err(1, "pread: buf %p, blk %d, len %u",
36 buf, (int) blkpos, bytelen);
38 #endif
40 struct ufs_info fs;
43 * Read contiguous sectors at once for speedup.
45 static size_t rq_len;
47 static void
48 raw_read_queue(void *buf, daddr_t blkpos, size_t bytelen)
49 /* bytelen: must be DEV_BSIZE aligned */
51 static daddr_t rq_start;
52 static char *rq_buf;
54 if (rq_len) {
55 if (bytelen && blkpos == rq_start + (ssize_t) btodb(rq_len)
56 && buf == rq_buf + rq_len) {
57 rq_len += bytelen;
58 return;
59 } else {
60 #ifdef DEBUG_WITH_STDIO
61 printf("raw_read_queue: read: buf %p, blk %d, len %d\n",
62 rq_buf, (int) rq_start, rq_len);
63 #endif
64 RAW_READ(rq_buf, rq_start, rq_len);
67 rq_buf = buf;
68 rq_start = blkpos;
69 rq_len = bytelen;
72 #define RAW_READ_QUEUE_INIT() (rq_len = 0)
73 #define RAW_READ_QUEUE_FLUSH() \
74 raw_read_queue((void *) 0, (daddr_t) 0, (size_t) 0)
78 * Read a file, specified by dinode.
79 * No support for holes or (short) symbolic links.
81 size_t
82 ufs_read(union ufs_dinode *di, void *buf, unsigned off, size_t count)
83 /* off: position in block */
85 struct ufs_info *ufsinfo = &fs;
86 size_t bsize = ufsinfo->bsize;
87 uint8_t *b = buf;
88 int i;
89 size_t disize, nread;
90 daddr_t pos;
91 #if defined(USE_UFS1) && defined(USE_UFS2)
92 enum ufs_ufstype uver = ufsinfo->ufstype;
93 #endif
95 #ifdef DEBUG_WITH_STDIO
96 printf("ufs_read: off: %d, count %u\n", off, count);
97 #endif
99 disize = DI_SIZE(di);
101 if (disize < count + off * bsize)
102 count = disize - off * bsize;
104 /* FS block size alignment. */
105 nread = count;
106 count = (count + bsize - 1) & ~(bsize - 1);
108 RAW_READ_QUEUE_INIT();
110 /* Read direct blocks. */
111 for ( ; off < NDADDR && count > 0; off++) {
112 #if defined(USE_UFS1) && defined(USE_UFS2)
113 if (uver == UFSTYPE_UFS1)
114 pos = di->di1.di_db[off];
115 else
116 pos = di->di2.di_db[off];
117 #else
118 pos = di->di_thisver.di_db[off];
119 #endif
120 #if 0
121 printf("ufs_read: read: blk: %d\n",
122 (int) pos << ufsinfo->fsbtodb);
123 #endif
124 raw_read_queue(b, pos << ufsinfo->fsbtodb, bsize);
125 b += bsize;
126 count -= bsize;
128 off -= NDADDR;
130 /* Read indirect blocks. */
131 for (i = 0; i < NIADDR && count > 0; i++) {
132 #if defined(USE_UFS1) && defined(USE_UFS2)
133 if (uver == UFSTYPE_UFS1)
134 pos = di->di1.di_ib[i];
135 else
136 pos = di->di2.di_ib[i];
137 #else
138 pos = di->di_thisver.di_ib[i];
139 #endif
140 count = ufs_read_indirect(pos, i, &b, &off, count);
143 RAW_READ_QUEUE_FLUSH();
145 return nread;
148 static int
149 ufs_read_indirect(daddr_t blk, int level, uint8_t **buf, unsigned *poff, size_t count)
150 /* poff: position in block */
152 struct ufs_info *ufsinfo = &fs;
153 size_t bsize = ufsinfo->bsize;
154 void *idbuf = alloca(bsize);
155 #ifdef USE_UFS1
156 int32_t *idbuf1 = idbuf;
157 #endif
158 #ifdef USE_UFS2
159 int64_t *idbuf2 = idbuf;
160 #endif
161 daddr_t pos;
162 unsigned off = *poff;
163 unsigned b;
165 #ifdef DEBUG_WITH_STDIO
166 printf("ufs_read_indirect: off: %d, count %u\n", off, count);
167 #endif
168 if (off) {
169 unsigned subindirsize = 1, indirsize;
170 int i;
172 for (i = level; i > 0; i--)
173 subindirsize *= ufsinfo->nindir;
174 indirsize = subindirsize * ufsinfo->nindir;
175 if (off >= indirsize) {
176 /* no need to read any data */
177 *poff = off - indirsize;
178 return 0;
181 b = off / subindirsize;
182 off -= b * subindirsize;
183 *poff = 0;
184 } else
185 b = 0;
187 /* read the indirect block */
188 RAW_READ(idbuf, blk << ufsinfo->fsbtodb, bsize);
190 for ( ; b < ufsinfo->nindir && count > 0; b++) {
191 #if defined(USE_UFS1) && defined(USE_UFS2)
192 if (ufsinfo->ufstype == UFSTYPE_UFS1)
193 #endif
194 #ifdef USE_UFS1
195 pos = idbuf1[b];
196 #endif
197 #if defined(USE_UFS1) && defined(USE_UFS2)
198 else
199 #endif
200 #ifdef USE_UFS2
201 pos = idbuf2[b];
202 #endif
204 if (level)
205 count = ufs_read_indirect(pos, level - 1, buf, &off, count);
206 else {
207 #if 0
208 printf("ufs_read: read: blk: %d\n",
209 (int) pos << ufsinfo->fsbtodb);
210 #endif
211 raw_read_queue(*buf, pos << ufsinfo->fsbtodb, bsize);
212 *buf += bsize;
213 count -= bsize;
217 return count;
221 * look-up fn in directory dirino
223 ino32_t
224 ufs_lookup(ino32_t dirino, const char *fn)
226 union ufs_dinode dirdi;
227 struct direct *pdir;
228 char *p, *endp;
229 size_t disize;
231 if (ufs_get_inode(dirino, &dirdi))
232 return 0;
234 if ((dirdi.di_common.di_mode & IFMT) != IFDIR)
235 return 0; /* Not a directory */
237 disize = DI_SIZE(&dirdi);
239 #if 0
240 p = alloca((disize + fs.bsize - 1) & ~(fs.bsize - 1));
241 #else /* simplify calculation to reduce code size */
242 p = alloca(disize + fs.bsize);
243 #endif
244 ufs_read(&dirdi, p, 0, disize);
245 endp = p + disize;
246 for ( ; pdir = (void *) p, p < endp; p += pdir->d_reclen) {
247 if (pdir->d_ino && !strcmp(fn, pdir->d_name))
248 return pdir->d_ino;
250 return 0; /* No such file or directory */
254 * look-up a file in absolute pathname from the root directory
256 ino32_t
257 ufs_lookup_path(const char *path)
259 char fn[FFS_MAXNAMLEN + 1];
260 char *p;
261 ino32_t ino = ROOTINO;
263 do {
264 while (*path == '/')
265 path++;
266 for (p = fn; *path && *path != '/'; )
267 *p++ = *path++;
268 *p++ = '\0';
269 ino = ufs_lookup(ino, fn);
270 } while (ino && *path);
272 return ino;
275 #if 0
276 size_t
277 ufs_load_file(void *buf, ino32_t dirino, const char *fn)
279 size_t cnt, disize;
280 union ufs_dinode dinode;
282 if (ufs_fn_inode(dirino, fn, &dinode))
283 return (unsigned) 0;
284 disize = DI_SIZE(&dinode);
285 cnt = ufs_read(&dinode, buf, 0, disize);
287 return cnt;
289 #endif
292 ufs_init(void)
294 return 1
295 #ifdef USE_FFS
296 && try_ffs()
297 #endif
298 #ifdef USE_LFS
299 && try_lfs()
300 #endif
304 #ifdef DEBUG_WITH_STDIO
305 void
306 ufs_list_dir(ino32_t dirino)
308 union ufs_dinode dirdi;
309 struct direct *pdir;
310 char *p, *endp;
311 size_t disize;
313 if (ufs_get_inode(dirino, &dirdi))
314 errx(1, "ino = %d: not found", dirino);
316 disize = DI_SIZE(&dirdi);
317 p = alloca((disize + fs.bsize - 1) & ~(fs.bsize - 1));
318 ufs_read(&dirdi, p, 0, disize);
319 endp = p + disize;
320 for ( ; pdir = (void *) p, p < endp; p += pdir->d_reclen) {
321 if (pdir->d_ino)
322 printf("%6d %s\n", pdir->d_ino, pdir->d_name);
325 #endif
327 #ifdef DEBUG_WITH_STDIO
329 main(argc, argv)
330 int argc __attribute__((unused));
331 char *argv[];
333 union ufs_dinode dinode;
335 if ((fd = open(argv[1], O_RDONLY)) < 0)
336 err(1, "open: %s", argv[1]);
338 if (ufs_init())
339 errx(1, "%s: unknown fs", argv[1]);
341 #if 1
342 ufs_list_dir(ROOTINO);
344 void *p;
345 size_t cnt;
346 ino32_t ino;
347 size_t disize;
349 if ((ino = ufs_lookup_path(argv[2])) == 0)
350 errx(1, "%s: not found", argv[2]);
351 ufs_get_inode(ino, &dinode);
352 disize = DI_SIZE(&dinode);
353 p = malloc((disize + fs.bsize - 1) & ~(fs.bsize - 1));
354 cnt = ufs_read(&dinode, p, 0, disize);
355 write(3, p, cnt);
356 free(p);
358 #endif
360 return 0;
362 #endif