xref: /netbsd-src/sbin/scan_ffs/scan_ffs.c (revision 3e7f0f50cad61a30884dabe3fe66198a39888a2b)
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