1*3e7f0f50Smlelstv /* $NetBSD: scan_ffs.c,v 1.37 2023/01/24 08:05:07 mlelstv Exp $ */
2b67b8509Sxtraeme
3b67b8509Sxtraeme /*
48b2678bdSxtraeme * Copyright (c) 2005-2007 Juan Romero Pardines
5b67b8509Sxtraeme * Copyright (c) 1998 Niklas Hallqvist, Tobias Weingartner
6b67b8509Sxtraeme * All rights reserved.
7b67b8509Sxtraeme *
8b67b8509Sxtraeme * Redistribution and use in source and binary forms, with or without
9b67b8509Sxtraeme * modification, are permitted provided that the following conditions
10b67b8509Sxtraeme * are met:
11b67b8509Sxtraeme * 1. Redistributions of source code must retain the above copyright
12b67b8509Sxtraeme * notice, this list of conditions and the following disclaimer.
13b67b8509Sxtraeme * 2. Redistributions in binary form must reproduce the above copyright
14b67b8509Sxtraeme * notice, this list of conditions and the following disclaimer in the
15b67b8509Sxtraeme * documentation and/or other materials provided with the distribution.
16b67b8509Sxtraeme *
17b67b8509Sxtraeme * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18b67b8509Sxtraeme * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19b67b8509Sxtraeme * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20b67b8509Sxtraeme * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21b67b8509Sxtraeme * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22b67b8509Sxtraeme * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23b67b8509Sxtraeme * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24b67b8509Sxtraeme * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25b67b8509Sxtraeme * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26b67b8509Sxtraeme * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27b67b8509Sxtraeme */
28b67b8509Sxtraeme
29b67b8509Sxtraeme /*
307cf1cb80Sxtraeme * Currently it can detect FFS and LFS partitions (version 1 or 2)
317cf1cb80Sxtraeme * up to 8192/65536 fragsize/blocksize.
32b67b8509Sxtraeme */
33b67b8509Sxtraeme
34b67b8509Sxtraeme #include <sys/cdefs.h>
35b67b8509Sxtraeme #ifndef lint
36*3e7f0f50Smlelstv __RCSID("$NetBSD: scan_ffs.c,v 1.37 2023/01/24 08:05:07 mlelstv Exp $");
37b67b8509Sxtraeme #endif /* not lint */
38b67b8509Sxtraeme
39b67b8509Sxtraeme #include <sys/types.h>
40b67b8509Sxtraeme #include <sys/param.h>
41b67b8509Sxtraeme #include <sys/disklabel.h>
42b67b8509Sxtraeme #include <sys/dkio.h>
43b67b8509Sxtraeme #include <sys/ioctl.h>
44b67b8509Sxtraeme #include <sys/fcntl.h>
45016ad359Sxtraeme #include <sys/mount.h>
46016ad359Sxtraeme
47016ad359Sxtraeme #include <ufs/lfs/lfs.h>
4834f0d74cSdholland #include <ufs/lfs/lfs_accessors.h>
49faaef229Sperseant #include <ufs/lfs/lfs_extern.h>
50488e14a7She
5175571afdSdholland #include <ufs/ufs/dinode.h>
52b67b8509Sxtraeme #include <ufs/ffs/fs.h>
53*3e7f0f50Smlelstv #include <ufs/ffs/ffs_extern.h>
54016ad359Sxtraeme
55b67b8509Sxtraeme #include <unistd.h>
56b67b8509Sxtraeme #include <stdlib.h>
57b67b8509Sxtraeme #include <stdio.h>
58b67b8509Sxtraeme #include <string.h>
59b67b8509Sxtraeme #include <err.h>
60b67b8509Sxtraeme #include <util.h>
6120f0ca00Schristos #include <paths.h>
62b67b8509Sxtraeme
637cf1cb80Sxtraeme #define BLK_CNT (blk + (n / 512))
647cf1cb80Sxtraeme
65016ad359Sxtraeme /* common struct for FFS/LFS */
66016ad359Sxtraeme struct sblockinfo {
67016ad359Sxtraeme struct lfs *lfs;
68016ad359Sxtraeme struct fs *ffs;
69a0a20469Sxtraeme uint64_t lfs_off;
70a0a20469Sxtraeme uint64_t ffs_off;
71016ad359Sxtraeme char lfs_path[MAXMNTLEN];
72016ad359Sxtraeme char ffs_path[MAXMNTLEN];
737cf1cb80Sxtraeme };
74b67b8509Sxtraeme
75b67b8509Sxtraeme static daddr_t blk, lastblk;
76b67b8509Sxtraeme
77016ad359Sxtraeme static int eflag = 0;
787aa92d97Sxtraeme static int fflag = 0;
79016ad359Sxtraeme static int flags = 0;
80016ad359Sxtraeme static int sbaddr = 0; /* counter for the LFS superblocks */
81b67b8509Sxtraeme
82016ad359Sxtraeme static char device[MAXPATHLEN];
83bebefe19Sxtraeme static const char *fstypes[] = { "NONE", "FFSv1", "FFSv2" };
84e0db7c68Schristos
85da1006fcSmrg static sig_atomic_t print_info = 0;
86da1006fcSmrg
87e0db7c68Schristos #define FSTYPE_NONE 0
88e0db7c68Schristos #define FSTYPE_FFSV1 1
89e0db7c68Schristos #define FSTYPE_FFSV2 2
90e0db7c68Schristos
91bebefe19Sxtraeme #define SBCOUNT 128 /* may be changed */
92016ad359Sxtraeme #define SBPASS (SBCOUNT * SBLOCKSIZE / 512)
93016ad359Sxtraeme
94016ad359Sxtraeme /* This is only useful for LFS */
95016ad359Sxtraeme
96016ad359Sxtraeme /* first sblock address contains the correct offset */
97016ad359Sxtraeme #define FIRST_SBLOCK_ADDRESS 1
98016ad359Sxtraeme /* second and third sblock address contain lfs_fsmnt[MAXMNTLEN] */
99016ad359Sxtraeme #define SECOND_SBLOCK_ADDRESS 2
100016ad359Sxtraeme /* last sblock address in a LFS partition */
101016ad359Sxtraeme #define MAX_SBLOCK_ADDRESS 10
102016ad359Sxtraeme
103faaef229Sperseant enum { NADA=0, VERBOSE=1, LABELS=2, BLOCKS=4 };
104016ad359Sxtraeme
105016ad359Sxtraeme /* FFS functions */
1067cf1cb80Sxtraeme static void ffs_printpart(struct sblockinfo *, int, size_t, int);
1077cf1cb80Sxtraeme static void ffs_scan(struct sblockinfo *, int);
1087cf1cb80Sxtraeme static int ffs_checkver(struct sblockinfo *);
109016ad359Sxtraeme /* LFS functions */
1107cf1cb80Sxtraeme static void lfs_printpart(struct sblockinfo *, int, int);
1117cf1cb80Sxtraeme static void lfs_scan(struct sblockinfo *, int);
112016ad359Sxtraeme /* common functions */
1138b0f9554Sperry static void usage(void) __dead;
114016ad359Sxtraeme static int scan_disk(int, daddr_t, daddr_t, int);
115016ad359Sxtraeme
116da1006fcSmrg static void
got_siginfo(int signo)117da1006fcSmrg got_siginfo(int signo)
118da1006fcSmrg {
119da1006fcSmrg
120da1006fcSmrg print_info = 1;
121da1006fcSmrg }
122da1006fcSmrg
123b67b8509Sxtraeme static int
ffs_checkver(struct sblockinfo * sbi)1247cf1cb80Sxtraeme ffs_checkver(struct sblockinfo *sbi)
125b67b8509Sxtraeme {
1267cf1cb80Sxtraeme switch (sbi->ffs->fs_magic) {
127*3e7f0f50Smlelstv case FS_UFS1_MAGIC_SWAPPED:
128*3e7f0f50Smlelstv case FS_UFS2_MAGIC_SWAPPED:
129*3e7f0f50Smlelstv case FS_UFS2EA_MAGIC_SWAPPED:
130*3e7f0f50Smlelstv ffs_sb_swap(sbi->ffs, sbi->ffs);
131*3e7f0f50Smlelstv break;
132*3e7f0f50Smlelstv }
133*3e7f0f50Smlelstv
134*3e7f0f50Smlelstv switch (sbi->ffs->fs_magic) {
135b67b8509Sxtraeme case FS_UFS1_MAGIC:
136b67b8509Sxtraeme case FS_UFS1_MAGIC_SWAPPED:
1377cf1cb80Sxtraeme sbi->ffs->fs_size = sbi->ffs->fs_old_size;
138e0db7c68Schristos return FSTYPE_FFSV1;
139b67b8509Sxtraeme case FS_UFS2_MAGIC:
14087ba0e2aSchs case FS_UFS2EA_MAGIC:
141b67b8509Sxtraeme case FS_UFS2_MAGIC_SWAPPED:
14287ba0e2aSchs case FS_UFS2EA_MAGIC_SWAPPED:
143e0db7c68Schristos return FSTYPE_FFSV2;
144b67b8509Sxtraeme default:
145e0db7c68Schristos return FSTYPE_NONE;
146b67b8509Sxtraeme }
147b67b8509Sxtraeme }
148b67b8509Sxtraeme
149b67b8509Sxtraeme static void
ffs_printpart(struct sblockinfo * sbi,int flag,size_t ffsize,int n)1507cf1cb80Sxtraeme ffs_printpart(struct sblockinfo *sbi, int flag, size_t ffsize, int n)
151b67b8509Sxtraeme {
152faaef229Sperseant int offset, ver;
153b67b8509Sxtraeme
154e0db7c68Schristos switch (flag) {
155e0db7c68Schristos case VERBOSE:
156bebefe19Sxtraeme switch (ffs_checkver(sbi)) {
1577cf1cb80Sxtraeme case FSTYPE_FFSV1:
1587cf1cb80Sxtraeme (void)printf("offset: %" PRIu64 " n: %d "
159bebefe19Sxtraeme "id: %x,%x size: %" PRIu64 "\n",
1607cf1cb80Sxtraeme BLK_CNT - (2 * SBLOCKSIZE / 512), n,
1617cf1cb80Sxtraeme sbi->ffs->fs_id[0], sbi->ffs->fs_id[1],
162bebefe19Sxtraeme (uint64_t)sbi->ffs->fs_size *
1637cf1cb80Sxtraeme sbi->ffs->fs_fsize / 512);
1647cf1cb80Sxtraeme break;
1657cf1cb80Sxtraeme case FSTYPE_FFSV2:
1667cf1cb80Sxtraeme (void)printf("offset: %" PRIu64 " n: %d "
167bebefe19Sxtraeme "id: %x,%x size: %" PRIu64 "\n",
1687cf1cb80Sxtraeme BLK_CNT - (ffsize * SBLOCKSIZE / 512+128),
1697cf1cb80Sxtraeme n, sbi->ffs->fs_id[0], sbi->ffs->fs_id[1],
170bebefe19Sxtraeme (uint64_t)sbi->ffs->fs_size *
1717cf1cb80Sxtraeme sbi->ffs->fs_fsize / 512);
1727cf1cb80Sxtraeme break;
1737cf1cb80Sxtraeme default:
1747cf1cb80Sxtraeme break;
1757cf1cb80Sxtraeme }
176e0db7c68Schristos break;
177e0db7c68Schristos case LABELS:
178e0db7c68Schristos (void)printf("X: %9" PRIu64,
179bebefe19Sxtraeme (uint64_t)(sbi->ffs->fs_size *
1807cf1cb80Sxtraeme sbi->ffs->fs_fsize / 512));
181bebefe19Sxtraeme switch (ffs_checkver(sbi)) {
182e0db7c68Schristos case FSTYPE_FFSV1:
183e0db7c68Schristos (void)printf(" %9" PRIu64,
1847cf1cb80Sxtraeme BLK_CNT - (ffsize * SBLOCKSIZE / 512));
185e0db7c68Schristos break;
186e0db7c68Schristos case FSTYPE_FFSV2:
187e0db7c68Schristos (void)printf(" %9" PRIu64,
1887cf1cb80Sxtraeme BLK_CNT - (ffsize * SBLOCKSIZE / 512 + 128));
189e0db7c68Schristos break;
190e0db7c68Schristos default:
191e0db7c68Schristos break;
192e0db7c68Schristos }
1934ef578d3Sxtraeme (void)printf(" 4.2BSD %6d %5d %7d # %s [%s]\n",
1947cf1cb80Sxtraeme sbi->ffs->fs_fsize, sbi->ffs->fs_bsize,
1957cf1cb80Sxtraeme sbi->ffs->fs_old_cpg,
196bebefe19Sxtraeme sbi->ffs_path, fstypes[ffs_checkver(sbi)]);
197e0db7c68Schristos break;
198faaef229Sperseant case BLOCKS:
199e0db7c68Schristos default:
200bebefe19Sxtraeme (void)printf("%s ", fstypes[ffs_checkver(sbi)]);
201faaef229Sperseant ver = ffs_checkver(sbi);
202faaef229Sperseant if (ver == FSTYPE_NONE)
203e0db7c68Schristos break;
204faaef229Sperseant
205faaef229Sperseant offset = 0;
206faaef229Sperseant if (flag == BLOCKS)
207faaef229Sperseant (void)printf("sb ");
208faaef229Sperseant else if (ver == FSTYPE_FFSV1)
209faaef229Sperseant offset = (2 * SBLOCKSIZE / 512);
210faaef229Sperseant else if (ver == FSTYPE_FFSV2)
211faaef229Sperseant offset = (ffsize * SBLOCKSIZE / 512 + 128);
212faaef229Sperseant
213faaef229Sperseant (void)printf("at %" PRIu64, BLK_CNT - offset);
214b67b8509Sxtraeme (void)printf(" size %" PRIu64 ", last mounted on %s\n",
215bebefe19Sxtraeme (uint64_t)(sbi->ffs->fs_size *
2167cf1cb80Sxtraeme sbi->ffs->fs_fsize / 512), sbi->ffs_path);
217e0db7c68Schristos break;
218b67b8509Sxtraeme }
219b67b8509Sxtraeme }
220b67b8509Sxtraeme
221b67b8509Sxtraeme static void
ffs_scan(struct sblockinfo * sbi,int n)2227cf1cb80Sxtraeme ffs_scan(struct sblockinfo *sbi, int n)
223b67b8509Sxtraeme {
2247cf1cb80Sxtraeme size_t i = 0;
225b67b8509Sxtraeme
226faaef229Sperseant if (flags & BLOCKS) {
227faaef229Sperseant ffs_printpart(sbi, BLOCKS, 0, n);
228faaef229Sperseant return;
229faaef229Sperseant }
230b67b8509Sxtraeme if (flags & VERBOSE)
2317cf1cb80Sxtraeme ffs_printpart(sbi, VERBOSE, NADA, n);
232bebefe19Sxtraeme switch (ffs_checkver(sbi)) {
233e0db7c68Schristos case FSTYPE_FFSV1:
2347cf1cb80Sxtraeme /* fsize/bsize > 512/4096 and < 4096/32768. */
2357cf1cb80Sxtraeme if ((BLK_CNT - lastblk) == (SBLOCKSIZE / 512)) {
2367cf1cb80Sxtraeme i = 2;
2377cf1cb80Sxtraeme /* fsize/bsize 4096/32768. */
2387cf1cb80Sxtraeme } else if ((BLK_CNT - lastblk) == (SBLOCKSIZE / 170)) {
2397cf1cb80Sxtraeme i = 4;
2407cf1cb80Sxtraeme /* fsize/bsize 8192/65536 */
2417cf1cb80Sxtraeme } else if ((BLK_CNT - lastblk) == (SBLOCKSIZE / 73)) {
2427cf1cb80Sxtraeme i = 8;
2437cf1cb80Sxtraeme } else
2447cf1cb80Sxtraeme break;
2457cf1cb80Sxtraeme
246b67b8509Sxtraeme if (flags & LABELS)
2477cf1cb80Sxtraeme ffs_printpart(sbi, LABELS, i, n);
248b67b8509Sxtraeme else
2497cf1cb80Sxtraeme ffs_printpart(sbi, NADA, i, n);
2507cf1cb80Sxtraeme
251e0db7c68Schristos break;
252e0db7c68Schristos case FSTYPE_FFSV2:
253b67b8509Sxtraeme /*
254b67b8509Sxtraeme * That checks for FFSv2 partitions with fragsize/blocksize:
255b67b8509Sxtraeme * 512/4096, 1024/8192, 2048/16384, 4096/32768 and 8192/65536.
256b67b8509Sxtraeme * Really enough for now.
257b67b8509Sxtraeme */
258e0db7c68Schristos for (i = 1; i < 16; i <<= 1)
259cefb0777Slukem if ((BLK_CNT - lastblk) == (daddr_t)(i * SBLOCKSIZE / 512)) {
260b67b8509Sxtraeme if (flags & LABELS)
2617cf1cb80Sxtraeme ffs_printpart(sbi, LABELS, i, n);
262b67b8509Sxtraeme else
2637cf1cb80Sxtraeme ffs_printpart(sbi, NADA, i, n);
264b67b8509Sxtraeme }
265016ad359Sxtraeme break;
266016ad359Sxtraeme }
267016ad359Sxtraeme }
268016ad359Sxtraeme
269016ad359Sxtraeme static void
lfs_printpart(struct sblockinfo * sbi,int flag,int n)2707cf1cb80Sxtraeme lfs_printpart(struct sblockinfo *sbi, int flag, int n)
271016ad359Sxtraeme {
272016ad359Sxtraeme if (flags & VERBOSE)
27395a8d28cSdholland (void)printf("offset: %" PRIu64 " size %" PRIu64
274f59b8f4bSdholland " fsid %" PRIx32 "\n", sbi->lfs_off,
275f59b8f4bSdholland lfs_sb_getsize(sbi->lfs),
276adca8af5Sdholland lfs_sb_getident(sbi->lfs));
277016ad359Sxtraeme switch (flag) {
278016ad359Sxtraeme case LABELS:
279016ad359Sxtraeme (void)printf("X: %9" PRIu64,
28095a8d28cSdholland (lfs_sb_getsize(sbi->lfs) *
281f59b8f4bSdholland lfs_sb_getfsize(sbi->lfs) / 512));
282016ad359Sxtraeme (void)printf(" %9" PRIu64, sbi->lfs_off);
2836ada0ed7Sdholland (void)printf(" 4.4LFS %6d %5d %7d # %s [LFS%d v%d]\n",
284f59b8f4bSdholland lfs_sb_getfsize(sbi->lfs), lfs_sb_getbsize(sbi->lfs),
285f59b8f4bSdholland lfs_sb_getnseg(sbi->lfs), sbi->lfs_path,
2866ada0ed7Sdholland sbi->lfs->lfs_is64 ? 64 : 32,
287992b9a23Sdholland lfs_sb_getversion(sbi->lfs));
288016ad359Sxtraeme break;
289faaef229Sperseant case BLOCKS:
2906ada0ed7Sdholland (void)printf("LFS%d v%d", sbi->lfs->lfs_is64 ? 64 : 32,
2916ada0ed7Sdholland lfs_sb_getversion(sbi->lfs));
292faaef229Sperseant (void)printf(" sb at %" PRIu64, sbi->lfs_off + btodb(LFS_LABELPAD));
293adca8af5Sdholland (void)printf(" fsid %" PRIx32, lfs_sb_getident(sbi->lfs));
294faaef229Sperseant (void)printf(" size %" PRIu64 ", last mounted on %s\n",
29595a8d28cSdholland (lfs_sb_getsize(sbi->lfs) *
296f59b8f4bSdholland lfs_sb_getfsize(sbi->lfs) / 512), sbi->lfs_path);
297faaef229Sperseant break;
298016ad359Sxtraeme default:
2996ada0ed7Sdholland (void)printf("LFS%d v%d ", sbi->lfs->lfs_is64 ? 64 : 32,
3006ada0ed7Sdholland lfs_sb_getversion(sbi->lfs));
3017cf1cb80Sxtraeme (void)printf("at %" PRIu64, sbi->lfs_off);
302016ad359Sxtraeme (void)printf(" size %" PRIu64 ", last mounted on %s\n",
30395a8d28cSdholland (lfs_sb_getsize(sbi->lfs) *
304f59b8f4bSdholland lfs_sb_getfsize(sbi->lfs) / 512), sbi->lfs_path);
305016ad359Sxtraeme break;
306016ad359Sxtraeme }
307016ad359Sxtraeme }
308016ad359Sxtraeme
309016ad359Sxtraeme static void
lfs_scan(struct sblockinfo * sbi,int n)3107cf1cb80Sxtraeme lfs_scan(struct sblockinfo *sbi, int n)
311016ad359Sxtraeme {
312adca8af5Sdholland size_t namesize;
313adca8af5Sdholland
314faaef229Sperseant /* Check to see if the sb checksums correctly */
3159e5184b8Sdholland if (lfs_sb_cksum(sbi->lfs) != lfs_sb_getcksum(sbi->lfs)) {
316faaef229Sperseant if (flags & VERBOSE)
317faaef229Sperseant printf("LFS bad superblock at %" PRIu64 "\n",
318faaef229Sperseant BLK_CNT);
319faaef229Sperseant return;
320faaef229Sperseant }
321faaef229Sperseant
322016ad359Sxtraeme /* backup offset */
3237cf1cb80Sxtraeme lastblk = BLK_CNT - (LFS_SBPAD / 512);
324016ad359Sxtraeme /* increment counter */
325016ad359Sxtraeme ++sbaddr;
326016ad359Sxtraeme
327faaef229Sperseant if (flags & BLOCKS) {
328faaef229Sperseant sbi->lfs_off = BLK_CNT - btodb(LFS_LABELPAD);
329faaef229Sperseant lfs_printpart(sbi, BLOCKS, n);
330faaef229Sperseant return;
331faaef229Sperseant }
332faaef229Sperseant
333016ad359Sxtraeme switch (sbaddr) {
334016ad359Sxtraeme /*
335016ad359Sxtraeme * first superblock contains the right offset, but lfs_fsmnt is
336faaef229Sperseant * empty... fortunately the next superblock address has it.
337016ad359Sxtraeme */
338016ad359Sxtraeme case FIRST_SBLOCK_ADDRESS:
339016ad359Sxtraeme /* copy partition offset */
340cefb0777Slukem if ((daddr_t)sbi->lfs_off != lastblk)
341faaef229Sperseant sbi->lfs_off = BLK_CNT - (LFS_LABELPAD / 512);
342016ad359Sxtraeme break;
343016ad359Sxtraeme case SECOND_SBLOCK_ADDRESS:
344016ad359Sxtraeme /* copy the path of last mount */
3459e5184b8Sdholland namesize = MIN(sizeof(sbi->lfs_path), MIN(
3469e5184b8Sdholland sizeof(sbi->lfs->lfs_dlfs_u.u_32.dlfs_fsmnt),
3479e5184b8Sdholland sizeof(sbi->lfs->lfs_dlfs_u.u_64.dlfs_fsmnt)));
3489e5184b8Sdholland (void)memcpy(sbi->lfs_path, lfs_sb_getfsmnt(sbi->lfs),
349adca8af5Sdholland namesize);
350adca8af5Sdholland sbi->lfs_path[namesize - 1] = '\0';
351016ad359Sxtraeme /* print now that we have the info */
352016ad359Sxtraeme if (flags & LABELS)
3537cf1cb80Sxtraeme lfs_printpart(sbi, LABELS, n);
354016ad359Sxtraeme else
3557cf1cb80Sxtraeme lfs_printpart(sbi, NADA, n);
356016ad359Sxtraeme /* clear our struct */
3577cf1cb80Sxtraeme (void)memset(sbi, 0, sizeof(*sbi));
358016ad359Sxtraeme break;
359016ad359Sxtraeme case MAX_SBLOCK_ADDRESS:
360016ad359Sxtraeme /*
361016ad359Sxtraeme * reset the counter, this is the last superblock address,
362016ad359Sxtraeme * the next one will be another partition maybe.
363016ad359Sxtraeme */
364016ad359Sxtraeme sbaddr = 0;
365016ad359Sxtraeme break;
366016ad359Sxtraeme default:
367016ad359Sxtraeme break;
368b67b8509Sxtraeme }
369b67b8509Sxtraeme }
370b67b8509Sxtraeme
371b67b8509Sxtraeme static int
lfs_checkmagic(struct sblockinfo * sbinfo)3726ada0ed7Sdholland lfs_checkmagic(struct sblockinfo *sbinfo)
3736ada0ed7Sdholland {
3746ada0ed7Sdholland switch (sbinfo->lfs->lfs_dlfs_u.u_32.dlfs_magic) {
3756ada0ed7Sdholland case LFS_MAGIC:
3766ada0ed7Sdholland sbinfo->lfs->lfs_is64 = false;
3776ada0ed7Sdholland sbinfo->lfs->lfs_dobyteswap = false;
3786ada0ed7Sdholland return 1;
3796ada0ed7Sdholland case LFS_MAGIC_SWAPPED:
3806ada0ed7Sdholland sbinfo->lfs->lfs_is64 = false;
3816ada0ed7Sdholland sbinfo->lfs->lfs_dobyteswap = true;
3826ada0ed7Sdholland return 1;
3836ada0ed7Sdholland case LFS64_MAGIC:
3846ada0ed7Sdholland sbinfo->lfs->lfs_is64 = true;
3856ada0ed7Sdholland sbinfo->lfs->lfs_dobyteswap = false;
3866ada0ed7Sdholland return 1;
3876ada0ed7Sdholland case LFS64_MAGIC_SWAPPED:
3886ada0ed7Sdholland sbinfo->lfs->lfs_is64 = true;
3896ada0ed7Sdholland sbinfo->lfs->lfs_dobyteswap = true;
3906ada0ed7Sdholland return 1;
3916ada0ed7Sdholland default:
3926ada0ed7Sdholland return 0;
3936ada0ed7Sdholland }
3946ada0ed7Sdholland }
3956ada0ed7Sdholland
39620f0ca00Schristos static void
show_status(uintmax_t beg,uintmax_t total)39720f0ca00Schristos show_status(uintmax_t beg, uintmax_t total)
39820f0ca00Schristos {
39920f0ca00Schristos static int ttyfd = -2;
40020f0ca00Schristos char buf[2048];
40120f0ca00Schristos const uintmax_t done = blk - beg;
40220f0ca00Schristos const double pcent = (100.0 * done) / total;
40320f0ca00Schristos int n;
40420f0ca00Schristos
40520f0ca00Schristos if (ttyfd == -2)
406ac31891aSchristos ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC);
40720f0ca00Schristos
40820f0ca00Schristos if (ttyfd == -1)
40920f0ca00Schristos return;
41020f0ca00Schristos
41120f0ca00Schristos n = snprintf(buf, sizeof(buf), "%s: done %ju of %ju blocks (%3.2f%%)\n",
41220f0ca00Schristos getprogname(), done, total, pcent);
41320f0ca00Schristos
41420f0ca00Schristos if (n <= 0)
41520f0ca00Schristos return;
41620f0ca00Schristos write(ttyfd, buf, (size_t)n);
41720f0ca00Schristos }
41820f0ca00Schristos
4196ada0ed7Sdholland static int
scan_disk(int fd,daddr_t beg,daddr_t end,int fflags)420016ad359Sxtraeme scan_disk(int fd, daddr_t beg, daddr_t end, int fflags)
421b67b8509Sxtraeme {
4227cf1cb80Sxtraeme struct sblockinfo sbinfo;
4237aa92d97Sxtraeme uint8_t buf[SBLOCKSIZE * SBCOUNT];
424bebefe19Sxtraeme int n;
425b67b8509Sxtraeme
426bebefe19Sxtraeme n = 0;
427b67b8509Sxtraeme lastblk = -1;
428016ad359Sxtraeme
429016ad359Sxtraeme /* clear our struct before using it */
430016ad359Sxtraeme (void)memset(&sbinfo, 0, sizeof(sbinfo));
431b67b8509Sxtraeme
432b67b8509Sxtraeme if (fflags & LABELS)
433e0db7c68Schristos (void)printf(
434016ad359Sxtraeme "# size offset fstype [fsize bsize cpg/sgs]\n");
435b67b8509Sxtraeme
436da1006fcSmrg const daddr_t total = end - beg;
437bebefe19Sxtraeme for (blk = beg; blk <= end; blk += SBPASS) {
438da1006fcSmrg if (print_info) {
43920f0ca00Schristos show_status(beg, total);
440da1006fcSmrg
441da1006fcSmrg print_info = 0;
442da1006fcSmrg }
443bebefe19Sxtraeme if (pread(fd, buf, sizeof(buf), blk * 512) == -1) {
444bebefe19Sxtraeme if (fflag && fd >= 0)
445bebefe19Sxtraeme (void)close(fd);
4464ef578d3Sxtraeme err(1, "pread");
447bebefe19Sxtraeme }
448b67b8509Sxtraeme
449b67b8509Sxtraeme for (n = 0; n < (SBLOCKSIZE * SBCOUNT); n += 512) {
450bebefe19Sxtraeme sbinfo.ffs = (struct fs *)&buf[n];
451bebefe19Sxtraeme sbinfo.lfs = (struct lfs *)&buf[n];
452bebefe19Sxtraeme
453bebefe19Sxtraeme switch (ffs_checkver(&sbinfo)) {
454016ad359Sxtraeme case FSTYPE_FFSV1:
455016ad359Sxtraeme case FSTYPE_FFSV2:
4567cf1cb80Sxtraeme ffs_scan(&sbinfo, n);
4577cf1cb80Sxtraeme lastblk = BLK_CNT;
458016ad359Sxtraeme (void)memcpy(sbinfo.ffs_path,
459016ad359Sxtraeme sbinfo.ffs->fs_fsmnt, MAXMNTLEN);
460016ad359Sxtraeme break;
461016ad359Sxtraeme case FSTYPE_NONE:
462016ad359Sxtraeme /* maybe LFS? */
4636ada0ed7Sdholland if (lfs_checkmagic(&sbinfo))
4647cf1cb80Sxtraeme lfs_scan(&sbinfo, n);
465016ad359Sxtraeme break;
466016ad359Sxtraeme default:
467016ad359Sxtraeme break;
468016ad359Sxtraeme }
469b67b8509Sxtraeme }
470b67b8509Sxtraeme }
471bebefe19Sxtraeme
472bebefe19Sxtraeme if (fflag && fd >= 0)
473bebefe19Sxtraeme (void)close(fd);
474bebefe19Sxtraeme
4754a74bb74Skleink return EXIT_SUCCESS;
476b67b8509Sxtraeme }
477b67b8509Sxtraeme
478b67b8509Sxtraeme
479b67b8509Sxtraeme static void
usage(void)480b6a23221Schristos usage(void)
481b67b8509Sxtraeme {
482b67b8509Sxtraeme (void)fprintf(stderr,
48359840910Sxtraeme "Usage: %s [-blv] [-e end] [-F file] [-s start] "
4847aa92d97Sxtraeme "device\n", getprogname());
4854a74bb74Skleink exit(EXIT_FAILURE);
486b67b8509Sxtraeme }
487b67b8509Sxtraeme
488b67b8509Sxtraeme
489b67b8509Sxtraeme int
main(int argc,char ** argv)490b67b8509Sxtraeme main(int argc, char **argv)
491b67b8509Sxtraeme {
492b67b8509Sxtraeme int ch, fd;
4937aa92d97Sxtraeme const char *fpath;
494b67b8509Sxtraeme daddr_t end = -1, beg = 0;
495b67b8509Sxtraeme struct disklabel dl;
496b67b8509Sxtraeme
4977aa92d97Sxtraeme fpath = NULL;
4987aa92d97Sxtraeme
499b6a23221Schristos setprogname(*argv);
500faaef229Sperseant while ((ch = getopt(argc, argv, "be:F:ls:v")) != -1)
501b67b8509Sxtraeme switch(ch) {
502faaef229Sperseant case 'b':
503faaef229Sperseant flags |= BLOCKS;
504faaef229Sperseant flags &= ~LABELS;
505faaef229Sperseant break;
506b67b8509Sxtraeme case 'e':
507b67b8509Sxtraeme eflag = 1;
508b67b8509Sxtraeme end = atoi(optarg);
509b67b8509Sxtraeme break;
51096734c01Sxtraeme case 'F':
5117aa92d97Sxtraeme fflag = 1;
5127aa92d97Sxtraeme fpath = optarg;
5137aa92d97Sxtraeme break;
514b67b8509Sxtraeme case 'l':
515b67b8509Sxtraeme flags |= LABELS;
516faaef229Sperseant flags &= ~BLOCKS;
517b67b8509Sxtraeme break;
518b67b8509Sxtraeme case 's':
519b67b8509Sxtraeme beg = atoi(optarg);
520b67b8509Sxtraeme break;
521b67b8509Sxtraeme case 'v':
522b67b8509Sxtraeme flags |= VERBOSE;
523b67b8509Sxtraeme break;
524b67b8509Sxtraeme default:
525b6a23221Schristos usage();
526b67b8509Sxtraeme /* NOTREACHED */
527b67b8509Sxtraeme }
528e0db7c68Schristos
529b67b8509Sxtraeme argc -= optind;
530b67b8509Sxtraeme argv += optind;
531b67b8509Sxtraeme
532da1006fcSmrg signal(SIGINFO, got_siginfo);
533da1006fcSmrg
5347aa92d97Sxtraeme if (fflag) {
5357aa92d97Sxtraeme struct stat stp;
5367aa92d97Sxtraeme
5377aa92d97Sxtraeme if (stat(fpath, &stp))
5387aa92d97Sxtraeme err(1, "Cannot stat `%s'", fpath);
5397aa92d97Sxtraeme
5407aa92d97Sxtraeme if (!eflag)
541a0a20469Sxtraeme end = (uint64_t)stp.st_size;
5427aa92d97Sxtraeme
543bebefe19Sxtraeme (void)printf("Total file size: %" PRIu64 "\n\n",
544bebefe19Sxtraeme (uint64_t)stp.st_size);
545bebefe19Sxtraeme
5463481053aSxtraeme fd = open(fpath, O_RDONLY | O_DIRECT);
5477aa92d97Sxtraeme } else {
548b67b8509Sxtraeme if (argc != 1)
549b6a23221Schristos usage();
550b67b8509Sxtraeme
551b67b8509Sxtraeme fd = opendisk(argv[0], O_RDONLY, device, sizeof(device), 0);
552b67b8509Sxtraeme
553e0db7c68Schristos if (ioctl(fd, DIOCGDINFO, &dl) == -1) {
554e0db7c68Schristos warn("Couldn't retrieve disklabel");
555e0db7c68Schristos (void)memset(&dl, 0, sizeof(dl));
556e0db7c68Schristos dl.d_secperunit = 0x7fffffff;
557e0db7c68Schristos } else {
558b67b8509Sxtraeme (void)printf("Disk: %s\n", dl.d_typename);
559b67b8509Sxtraeme (void)printf("Total sectors on disk: %" PRIu32 "\n\n",
560b67b8509Sxtraeme dl.d_secperunit);
561b67b8509Sxtraeme }
5627aa92d97Sxtraeme }
563b67b8509Sxtraeme
5647aa92d97Sxtraeme if (!eflag && !fflag)
565b67b8509Sxtraeme end = dl.d_secperunit; /* default to max sectors */
566b67b8509Sxtraeme
5677aa92d97Sxtraeme if (fd == -1)
5687aa92d97Sxtraeme err(1, "Cannot open `%s'", device);
5697aa92d97Sxtraeme /* NOTREACHED */
5707aa92d97Sxtraeme
571016ad359Sxtraeme return scan_disk(fd, beg, end, flags);
572b67b8509Sxtraeme }
573