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