scan_ffs.c revision 1.14 1 /* $NetBSD: scan_ffs.c,v 1.14 2006/10/14 13:22:34 xtraeme Exp $ */
2
3 /*
4 * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Juan Romero Pardines.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Juan Romero Pardines
21 * for the NetBSD Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1998 Niklas Hallqvist, Tobias Weingartner
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 */
63
64 /*
65 * Currently it can detect FFS and LFS partitions (version 1 or 2)
66 * up to 8192/65536 fragsize/blocksize.
67 */
68
69 #include <sys/cdefs.h>
70 #ifndef lint
71 __RCSID("$NetBSD: scan_ffs.c,v 1.14 2006/10/14 13:22:34 xtraeme Exp $");
72 #endif /* not lint */
73
74 #include <sys/types.h>
75 #include <sys/param.h>
76 #include <sys/disklabel.h>
77 #include <sys/dkio.h>
78 #include <sys/ioctl.h>
79 #include <sys/fcntl.h>
80 #include <sys/queue.h>
81 #include <sys/mount.h>
82
83 #include <ufs/ufs/dinode.h>
84 #include <ufs/lfs/lfs.h>
85
86 /* Undefine macros defined by both lfs/lfs.h and ffs/fs.h */
87 #undef fsbtodb
88 #undef dbtofsb
89 #undef blkoff
90 #undef fragoff
91 #undef lblktosize
92 #undef lblkno
93 #undef numfrags
94 #undef blkroundup
95 #undef fragroundup
96 #undef fragstoblks
97 #undef blkstofrags
98 #undef fragnum
99 #undef blknum
100 #undef blksize
101 #undef INOPB
102 #undef INOPF
103 #undef NINDIR
104
105 #include <ufs/ffs/fs.h>
106
107 /* Undefine macros defined by both lfs/lfs.h and ffs/fs.h */
108 /* ...to make sure we don't later depend on their (ambigious) definition */
109 #undef fsbtodb
110 #undef dbtofsb
111 #undef blkoff
112 #undef fragoff
113 #undef lblktosize
114 #undef lblkno
115 #undef numfrags
116 #undef blkroundup
117 #undef fragroundup
118 #undef fragstoblks
119 #undef blkstofrags
120 #undef fragnum
121 #undef blknum
122 #undef blksize
123 #undef INOPB
124 #undef INOPF
125 #undef NINDIR
126
127 #include <unistd.h>
128 #include <stdlib.h>
129 #include <stdio.h>
130 #include <string.h>
131 #include <err.h>
132 #include <util.h>
133
134 #define BLK_CNT (blk + (n / 512))
135
136 /* common struct for FFS/LFS */
137 struct sblockinfo {
138 struct lfs *lfs;
139 struct fs *ffs;
140 uint64_t lfs_off;
141 uint64_t ffs_off;
142 char lfs_path[MAXMNTLEN];
143 char ffs_path[MAXMNTLEN];
144 };
145
146 static daddr_t blk, lastblk;
147
148 static int eflag = 0;
149 static int fflag = 0;
150 static int flags = 0;
151 static int sbaddr = 0; /* counter for the LFS superblocks */
152
153 static char device[MAXPATHLEN];
154 static const char *fstypes[] = { "NONE", "FFSv1", "FFSv2", "LFS" };
155
156 #define FSTYPE_NONE 0
157 #define FSTYPE_FFSV1 1
158 #define FSTYPE_FFSV2 2
159
160 #define SBCOUNT 64 /* may be changed */
161 #define SBPASS (SBCOUNT * SBLOCKSIZE / 512)
162
163 /* This is only useful for LFS */
164
165 /* first sblock address contains the correct offset */
166 #define FIRST_SBLOCK_ADDRESS 1
167 /* second and third sblock address contain lfs_fsmnt[MAXMNTLEN] */
168 #define SECOND_SBLOCK_ADDRESS 2
169 /* last sblock address in a LFS partition */
170 #define MAX_SBLOCK_ADDRESS 10
171
172 enum { NADA, VERBOSE, LABELS };
173
174 /* FFS functions */
175 static void ffs_printpart(struct sblockinfo *, int, size_t, int);
176 static void ffs_scan(struct sblockinfo *, int);
177 static int ffs_checkver(struct sblockinfo *);
178 /* LFS functions */
179 static void lfs_printpart(struct sblockinfo *, int, int);
180 static void lfs_scan(struct sblockinfo *, int);
181 /* common functions */
182 static void usage(void) __attribute__((__noreturn__));
183 static int scan_disk(int, daddr_t, daddr_t, int);
184
185 static int
186 ffs_checkver(struct sblockinfo *sbi)
187 {
188 switch (sbi->ffs->fs_magic) {
189 case FS_UFS1_MAGIC:
190 case FS_UFS1_MAGIC_SWAPPED:
191 sbi->ffs->fs_size = sbi->ffs->fs_old_size;
192 return FSTYPE_FFSV1;
193 case FS_UFS2_MAGIC:
194 case FS_UFS2_MAGIC_SWAPPED:
195 return FSTYPE_FFSV2;
196 default:
197 return FSTYPE_NONE;
198 }
199 }
200
201 static void
202 ffs_printpart(struct sblockinfo *sbi, int flag, size_t ffsize, int n)
203 {
204
205 int fstype = ffs_checkver(sbi);
206
207 switch (flag) {
208 case VERBOSE:
209 switch (fstype) {
210 case FSTYPE_FFSV1:
211 (void)printf("offset: %" PRIu64 " n: %d "
212 "id %x,%x size: %" PRIu64 "\n",
213 BLK_CNT - (2 * SBLOCKSIZE / 512), n,
214 sbi->ffs->fs_id[0], sbi->ffs->fs_id[1],
215 (uint64_t)(off_t)sbi->ffs->fs_size *
216 sbi->ffs->fs_fsize / 512);
217 break;
218 case FSTYPE_FFSV2:
219 (void)printf("offset: %" PRIu64 " n: %d "
220 "id %x,%x size: %" PRIu64 "\n",
221 BLK_CNT - (ffsize * SBLOCKSIZE / 512+128),
222 n, sbi->ffs->fs_id[0], sbi->ffs->fs_id[1],
223 (uint64_t)(off_t)sbi->ffs->fs_size *
224 sbi->ffs->fs_fsize / 512);
225 break;
226 default:
227 break;
228 }
229 break;
230 case LABELS:
231 (void)printf("X: %9" PRIu64,
232 (uint64_t)((off_t)sbi->ffs->fs_size *
233 sbi->ffs->fs_fsize / 512));
234 switch (fstype) {
235 case FSTYPE_FFSV1:
236 (void)printf(" %9" PRIu64,
237 BLK_CNT - (ffsize * SBLOCKSIZE / 512));
238 break;
239 case FSTYPE_FFSV2:
240 (void)printf(" %9" PRIu64,
241 BLK_CNT - (ffsize * SBLOCKSIZE / 512 + 128));
242 break;
243 default:
244 break;
245 }
246 (void)printf(" 4.2BSD %6d %5d %7d # %s [%s]\n",
247 sbi->ffs->fs_fsize, sbi->ffs->fs_bsize,
248 sbi->ffs->fs_old_cpg,
249 sbi->ffs_path, fstypes[fstype]);
250 break;
251 default:
252 (void)printf("%s ", fstypes[fstype]);
253 switch (fstype) {
254 case FSTYPE_FFSV1:
255 (void)printf("at %" PRIu64,
256 BLK_CNT - (2 * SBLOCKSIZE / 512));
257 break;
258 case FSTYPE_FFSV2:
259 (void)printf("at %" PRIu64,
260 BLK_CNT - (ffsize * SBLOCKSIZE / 512 + 128));
261 break;
262 default:
263 break;
264 }
265 (void)printf(" size %" PRIu64 ", last mounted on %s\n",
266 (uint64_t)((off_t)sbi->ffs->fs_size *
267 sbi->ffs->fs_fsize / 512), sbi->ffs_path);
268 break;
269 }
270 }
271
272 static void
273 ffs_scan(struct sblockinfo *sbi, int n)
274 {
275 int fstype = ffs_checkver(sbi);
276 size_t i = 0;
277
278 if (flags & VERBOSE)
279 ffs_printpart(sbi, VERBOSE, NADA, n);
280 switch (fstype) {
281 case FSTYPE_FFSV1:
282 /* fsize/bsize > 512/4096 and < 4096/32768. */
283 if ((BLK_CNT - lastblk) == (SBLOCKSIZE / 512)) {
284 i = 2;
285 /* fsize/bsize 4096/32768. */
286 } else if ((BLK_CNT - lastblk) == (SBLOCKSIZE / 170)) {
287 i = 4;
288 /* fsize/bsize 8192/65536 */
289 } else if ((BLK_CNT - lastblk) == (SBLOCKSIZE / 73)) {
290 i = 8;
291 } else
292 break;
293
294 if (flags & LABELS)
295 ffs_printpart(sbi, LABELS, i, n);
296 else
297 ffs_printpart(sbi, NADA, i, n);
298
299 break;
300 case FSTYPE_FFSV2:
301 /*
302 * That checks for FFSv2 partitions with fragsize/blocksize:
303 * 512/4096, 1024/8192, 2048/16384, 4096/32768 and 8192/65536.
304 * Really enough for now.
305 */
306 for (i = 1; i < 16; i <<= 1)
307 if ((BLK_CNT - lastblk) == (i * SBLOCKSIZE / 512)) {
308 if (flags & LABELS)
309 ffs_printpart(sbi, LABELS, i, n);
310 else
311 ffs_printpart(sbi, NADA, i, n);
312 }
313 break;
314 }
315 }
316
317 static void
318 lfs_printpart(struct sblockinfo *sbi, int flag, int n)
319 {
320 if (flags & VERBOSE)
321 (void)printf("offset: %" PRIu64 " size %" PRIu32 "\n",
322 sbi->lfs_off, sbi->lfs->lfs_size);
323 switch (flag) {
324 case LABELS:
325 (void)printf("X: %9" PRIu64,
326 (uint64_t)((off_t)sbi->lfs->lfs_size *
327 sbi->lfs->lfs_fsize / 512));
328 (void)printf(" %9" PRIu64, sbi->lfs_off);
329 (void)printf(" 4.4LFS %6d %5d %7d # %s [LFSv%d]\n",
330 sbi->lfs->lfs_fsize, sbi->lfs->lfs_bsize,
331 sbi->lfs->lfs_nseg, sbi->lfs_path,
332 sbi->lfs->lfs_version);
333 break;
334 default:
335 (void)printf("LFSv%d ", sbi->lfs->lfs_version);
336 (void)printf("at %" PRIu64, sbi->lfs_off);
337 (void)printf(" size %" PRIu64 ", last mounted on %s\n",
338 (uint64_t)((off_t)sbi->lfs->lfs_size *
339 sbi->lfs->lfs_fsize / 512), sbi->lfs_path);
340 break;
341 }
342 }
343
344 static void
345 lfs_scan(struct sblockinfo *sbi, int n)
346 {
347 /* backup offset */
348 lastblk = BLK_CNT - (LFS_SBPAD / 512);
349 /* increment counter */
350 ++sbaddr;
351
352 switch (sbaddr) {
353 /*
354 * first superblock contains the right offset, but lfs_fsmnt is
355 * empty... afortunately the next superblock address has it.
356 */
357 case FIRST_SBLOCK_ADDRESS:
358 /* copy partition offset */
359 if (sbi->lfs_off != lastblk)
360 sbi->lfs_off = BLK_CNT - (LFS_SBPAD / 512);
361 break;
362 case SECOND_SBLOCK_ADDRESS:
363 /* copy the path of last mount */
364 (void)memcpy(sbi->lfs_path, sbi->lfs->lfs_fsmnt, MAXMNTLEN);
365 /* print now that we have the info */
366 if (flags & LABELS)
367 lfs_printpart(sbi, LABELS, n);
368 else
369 lfs_printpart(sbi, NADA, n);
370 /* clear our struct */
371 (void)memset(sbi, 0, sizeof(*sbi));
372 break;
373 case MAX_SBLOCK_ADDRESS:
374 /*
375 * reset the counter, this is the last superblock address,
376 * the next one will be another partition maybe.
377 */
378 sbaddr = 0;
379 break;
380 default:
381 break;
382 }
383 }
384
385 static int
386 scan_disk(int fd, daddr_t beg, daddr_t end, int fflags)
387 {
388 struct sblockinfo sbinfo;
389 uint8_t buf[SBLOCKSIZE * SBCOUNT];
390 int n, fstype;
391
392 n = fstype = 0;
393 lastblk = -1;
394
395 /* clear our struct before using it */
396 (void)memset(&sbinfo, 0, sizeof(sbinfo));
397
398 if (fflags & LABELS)
399 (void)printf(
400 "# size offset fstype [fsize bsize cpg/sgs]\n");
401
402 for (blk = beg; blk <= ((end < 0) ? blk: end); blk += SBPASS) {
403 (void)memset(&buf, 0, sizeof(buf));
404
405 if (pread(fd, buf, sizeof(buf), (off_t)blk * 512) == (off_t)-1)
406 err(1, "pread");
407
408 for (n = 0; n < (SBLOCKSIZE * SBCOUNT); n += 512) {
409 sbinfo.ffs = (struct fs *)(void *)&buf[n];
410 sbinfo.lfs = (struct lfs *)(void *)&buf[n];
411 fstype = ffs_checkver(&sbinfo);
412 switch (fstype) {
413 case FSTYPE_FFSV1:
414 case FSTYPE_FFSV2:
415 ffs_scan(&sbinfo, n);
416 lastblk = BLK_CNT;
417 (void)memcpy(sbinfo.ffs_path,
418 sbinfo.ffs->fs_fsmnt, MAXMNTLEN);
419 break;
420 case FSTYPE_NONE:
421 /* maybe LFS? */
422 if (sbinfo.lfs->lfs_magic == LFS_MAGIC)
423 lfs_scan(&sbinfo, n);
424 break;
425 default:
426 break;
427 }
428 }
429 }
430 return EXIT_SUCCESS;
431 }
432
433
434 static void
435 usage(void)
436 {
437 (void)fprintf(stderr,
438 "Usage: %s [-lv] [-e end] [-F file] [-s start] "
439 "device\n", getprogname());
440 exit(EXIT_FAILURE);
441 }
442
443
444 int
445 main(int argc, char **argv)
446 {
447 int ch, fd;
448 const char *fpath;
449 daddr_t end = -1, beg = 0;
450 struct disklabel dl;
451
452 fpath = NULL;
453
454 setprogname(*argv);
455 while ((ch = getopt(argc, argv, "e:F:ls:v")) != -1)
456 switch(ch) {
457 case 'e':
458 eflag = 1;
459 end = atoi(optarg);
460 break;
461 case 'F':
462 fflag = 1;
463 fpath = optarg;
464 break;
465 case 'l':
466 flags |= LABELS;
467 break;
468 case 's':
469 beg = atoi(optarg);
470 break;
471 case 'v':
472 flags |= VERBOSE;
473 break;
474 default:
475 usage();
476 /* NOTREACHED */
477 }
478
479 argc -= optind;
480 argv += optind;
481
482 if (fflag) {
483 struct stat stp;
484
485 if (stat(fpath, &stp))
486 err(1, "Cannot stat `%s'", fpath);
487
488 if (!eflag)
489 end = (uint64_t)stp.st_size;
490
491 fd = open(fpath, O_RDONLY);
492 } else {
493 if (argc != 1)
494 usage();
495
496 fd = opendisk(argv[0], O_RDONLY, device, sizeof(device), 0);
497
498 if (ioctl(fd, DIOCGDINFO, &dl) == -1) {
499 warn("Couldn't retrieve disklabel");
500 (void)memset(&dl, 0, sizeof(dl));
501 dl.d_secperunit = 0x7fffffff;
502 } else {
503 (void)printf("Disk: %s\n", dl.d_typename);
504 (void)printf("Total sectors on disk: %" PRIu32 "\n\n",
505 dl.d_secperunit);
506 }
507 }
508
509 if (!eflag && !fflag)
510 end = dl.d_secperunit; /* default to max sectors */
511
512 if (fd == -1)
513 err(1, "Cannot open `%s'", device);
514 /* NOTREACHED */
515
516 return scan_disk(fd, beg, end, flags);
517 }
518