scan_ffs.c revision 1.3 1 1.3 christos /* $NetBSD: scan_ffs.c,v 1.3 2005/06/15 20:03:03 christos Exp $ */
2 1.1 xtraeme /* $OpenBSD: scan_ffs.c,v 1.11 2004/02/16 19:13:03 deraadt Exp$ */
3 1.1 xtraeme
4 1.1 xtraeme /*
5 1.1 xtraeme * Copyright (c) 2005 Juan Romero Pardines
6 1.1 xtraeme * Copyright (c) 1998 Niklas Hallqvist, Tobias Weingartner
7 1.1 xtraeme * All rights reserved.
8 1.1 xtraeme *
9 1.1 xtraeme * Redistribution and use in source and binary forms, with or without
10 1.1 xtraeme * modification, are permitted provided that the following conditions
11 1.1 xtraeme * are met:
12 1.1 xtraeme * 1. Redistributions of source code must retain the above copyright
13 1.1 xtraeme * notice, this list of conditions and the following disclaimer.
14 1.1 xtraeme * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 xtraeme * notice, this list of conditions and the following disclaimer in the
16 1.1 xtraeme * documentation and/or other materials provided with the distribution.
17 1.1 xtraeme *
18 1.1 xtraeme * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 1.1 xtraeme * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 1.1 xtraeme * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 1.1 xtraeme * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 1.1 xtraeme * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 1.1 xtraeme * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 1.1 xtraeme * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 1.1 xtraeme * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 1.1 xtraeme * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 1.1 xtraeme * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 1.1 xtraeme */
29 1.1 xtraeme
30 1.1 xtraeme /*
31 1.1 xtraeme * Currently it can detect:
32 1.1 xtraeme * o FFSv1 with fragsize/blocksize: 512/4096, 1024/8192, 2048/16384.
33 1.1 xtraeme * o FFSv2 with fragsize/blocksize: 512/4096, 1024/8192, 2048/16384,
34 1.1 xtraeme * 4096/32768, 8192/65536.
35 1.1 xtraeme * TODO:
36 1.1 xtraeme * o Detect FFSv1 partitions with fsize/bsize > 2048/16384.
37 1.1 xtraeme * o Detect FFSv2 partitions with fsize/bsize > 8192/65536.
38 1.1 xtraeme */
39 1.1 xtraeme
40 1.1 xtraeme #include <sys/cdefs.h>
41 1.1 xtraeme #ifndef lint
42 1.3 christos __RCSID("$NetBSD: scan_ffs.c,v 1.3 2005/06/15 20:03:03 christos Exp $");
43 1.1 xtraeme #endif /* not lint */
44 1.1 xtraeme
45 1.1 xtraeme #include <sys/types.h>
46 1.1 xtraeme #include <sys/param.h>
47 1.1 xtraeme
48 1.1 xtraeme #include <sys/disklabel.h>
49 1.1 xtraeme #include <sys/dkio.h>
50 1.1 xtraeme #include <sys/ioctl.h>
51 1.1 xtraeme #include <sys/fcntl.h>
52 1.1 xtraeme #include <ufs/ffs/fs.h>
53 1.1 xtraeme #include <unistd.h>
54 1.1 xtraeme #include <stdlib.h>
55 1.1 xtraeme #include <stdio.h>
56 1.1 xtraeme #include <string.h>
57 1.1 xtraeme #include <err.h>
58 1.1 xtraeme #include <util.h>
59 1.1 xtraeme
60 1.1 xtraeme enum { NADA, VERBOSE, LABELS };
61 1.1 xtraeme
62 1.1 xtraeme #define SBCOUNT 64 /* XXX should be configurable */
63 1.1 xtraeme
64 1.1 xtraeme static void printpart(int, int, int);
65 1.1 xtraeme static void ufsmagic(int);
66 1.1 xtraeme static void usage(void) __attribute__((__noreturn__));
67 1.1 xtraeme static int checkfstype(void);
68 1.1 xtraeme static int ufsscan(int, daddr_t, daddr_t, int);
69 1.1 xtraeme
70 1.1 xtraeme static char lastmount[MAXMNTLEN];
71 1.1 xtraeme static char device[MAXPATHLEN];
72 1.1 xtraeme
73 1.1 xtraeme static int eflag = 0;
74 1.1 xtraeme static int flags = 0;
75 1.1 xtraeme
76 1.1 xtraeme static daddr_t blk, lastblk;
77 1.1 xtraeme
78 1.1 xtraeme static struct fs *sb;
79 1.1 xtraeme
80 1.3 christos static const char *fstypes[] = { "NONE", "FFSv1", "FFSv2" };
81 1.3 christos
82 1.3 christos #define FSTYPE_NONE 0
83 1.3 christos #define FSTYPE_FFSV1 1
84 1.3 christos #define FSTYPE_FFSV2 2
85 1.3 christos
86 1.1 xtraeme static int
87 1.1 xtraeme checkfstype(void)
88 1.1 xtraeme {
89 1.1 xtraeme switch (sb->fs_magic) {
90 1.1 xtraeme case FS_UFS1_MAGIC:
91 1.1 xtraeme case FS_UFS1_MAGIC_SWAPPED:
92 1.1 xtraeme sb->fs_size = sb->fs_old_size;
93 1.3 christos return FSTYPE_FFSV1;
94 1.1 xtraeme case FS_UFS2_MAGIC:
95 1.1 xtraeme case FS_UFS2_MAGIC_SWAPPED:
96 1.3 christos return FSTYPE_FFSV2;
97 1.1 xtraeme default:
98 1.3 christos return FSTYPE_NONE;
99 1.1 xtraeme }
100 1.1 xtraeme }
101 1.1 xtraeme
102 1.1 xtraeme static void
103 1.1 xtraeme printpart(int flag, int ffsize, int n)
104 1.1 xtraeme {
105 1.1 xtraeme
106 1.3 christos int fstype = checkfstype();
107 1.1 xtraeme
108 1.3 christos switch (flag) {
109 1.3 christos case VERBOSE:
110 1.3 christos (void)printf("block: %" PRIu64 "id %x,%x size %" PRIu64 "\n",
111 1.3 christos blk + (n / 512), sb->fs_id[0], sb->fs_id[1], sb->fs_size);
112 1.3 christos break;
113 1.3 christos case LABELS:
114 1.3 christos (void)printf("X: %9" PRIu64,
115 1.3 christos (uint64_t)((off_t)sb->fs_size * sb->fs_fsize / 512));
116 1.3 christos switch (fstype) {
117 1.3 christos case FSTYPE_FFSV1:
118 1.3 christos (void)printf(" %9" PRIu64,
119 1.3 christos blk + (n / 512) - (2 * SBLOCKSIZE / 512));
120 1.3 christos break;
121 1.3 christos case FSTYPE_FFSV2:
122 1.3 christos (void)printf(" %9" PRIu64,
123 1.3 christos blk + (n / 512) -
124 1.3 christos (ffsize * SBLOCKSIZE / 512 + 128));
125 1.3 christos break;
126 1.3 christos default:
127 1.3 christos break;
128 1.3 christos }
129 1.1 xtraeme (void)printf(" 4.2BSD %6d %5d%4d # %s [%s]\n",
130 1.1 xtraeme sb->fs_fsize, sb->fs_bsize,
131 1.3 christos sb->fs_old_cpg, lastmount, fstypes[fstype]);
132 1.3 christos break;
133 1.3 christos default:
134 1.3 christos printf("%s ", fstypes[fstype]);
135 1.3 christos switch (fstype) {
136 1.3 christos case FSTYPE_FFSV1:
137 1.3 christos (void)printf("at %" PRIu64,
138 1.3 christos blk + (n / 512) - (2 * SBLOCKSIZE / 512));
139 1.3 christos break;
140 1.3 christos case FSTYPE_FFSV2:
141 1.3 christos (void)printf("at %" PRIu64,
142 1.3 christos blk + (n / 512) -
143 1.3 christos (ffsize * SBLOCKSIZE / 512 + 128));
144 1.3 christos break;
145 1.3 christos default:
146 1.3 christos break;
147 1.3 christos }
148 1.1 xtraeme (void)printf(" size %" PRIu64 ", last mounted on %s\n",
149 1.3 christos (uint64_t)((off_t)sb->fs_size * sb->fs_fsize / 512),
150 1.3 christos lastmount);
151 1.3 christos break;
152 1.1 xtraeme }
153 1.1 xtraeme }
154 1.1 xtraeme
155 1.1 xtraeme static void
156 1.1 xtraeme ufsmagic(int n)
157 1.1 xtraeme {
158 1.3 christos int fstype = checkfstype();
159 1.3 christos size_t i;
160 1.1 xtraeme
161 1.1 xtraeme /*
162 1.1 xtraeme * FIXME:
163 1.1 xtraeme * It cannot find FFSv1 partitions with fsize/bsize > 2048/16384,
164 1.1 xtraeme * same problem found in the original program that comes from
165 1.1 xtraeme * OpenBSD (scan_ffs(1)).
166 1.1 xtraeme */
167 1.1 xtraeme if (flags & VERBOSE)
168 1.1 xtraeme printpart(VERBOSE, NADA, n);
169 1.3 christos switch (fstype) {
170 1.3 christos case FSTYPE_FFSV1:
171 1.1 xtraeme if (((blk + (n / 512)) - lastblk) == (SBLOCKSIZE / 512)) {
172 1.1 xtraeme if (flags & LABELS)
173 1.1 xtraeme printpart(LABELS, NADA, n);
174 1.1 xtraeme else
175 1.1 xtraeme printpart(NADA, NADA, n);
176 1.1 xtraeme }
177 1.3 christos break;
178 1.3 christos case FSTYPE_FFSV2:
179 1.3 christos /*
180 1.3 christos * That checks for FFSv2 partitions with fragsize/blocksize:
181 1.3 christos * 512/4096, 1024/8192, 2048/16384, 4096/32768 and 8192/65536.
182 1.3 christos * Really enough for now.
183 1.3 christos */
184 1.3 christos for (i = 1; i < 16; i <<= 1)
185 1.3 christos if (((blk + (n / 512)) - lastblk) ==
186 1.3 christos (i * SBLOCKSIZE / 512)) {
187 1.3 christos if (flags & LABELS)
188 1.3 christos printpart(LABELS, i, n);
189 1.3 christos else
190 1.3 christos printpart(NADA, i, n);
191 1.3 christos }
192 1.1 xtraeme }
193 1.1 xtraeme }
194 1.1 xtraeme
195 1.1 xtraeme static int
196 1.1 xtraeme ufsscan(int fd, daddr_t beg, daddr_t end, int fflags)
197 1.1 xtraeme {
198 1.1 xtraeme
199 1.1 xtraeme u_int8_t buf[SBLOCKSIZE * SBCOUNT];
200 1.3 christos int n, fstype;
201 1.1 xtraeme
202 1.1 xtraeme lastblk = -1;
203 1.3 christos (void)memset(lastmount, 0, MAXMNTLEN);
204 1.1 xtraeme
205 1.1 xtraeme if (fflags & LABELS)
206 1.3 christos (void)printf(
207 1.3 christos "# size offset fstype [fsize bsize cpg]\n");
208 1.1 xtraeme
209 1.1 xtraeme for (blk = beg; blk <= ((end < 0) ? blk: end);
210 1.1 xtraeme blk += (SBCOUNT * SBLOCKSIZE / 512)) {
211 1.3 christos (void)memset(buf, 0, sizeof(buf));
212 1.1 xtraeme
213 1.3 christos if (lseek(fd, (off_t)blk * 512, SEEK_SET) == (off_t)-1)
214 1.1 xtraeme err(1, "lseek");
215 1.1 xtraeme
216 1.3 christos if (read(fd, buf, sizeof(buf)) == -1)
217 1.1 xtraeme err(1, "read");
218 1.1 xtraeme
219 1.1 xtraeme for (n = 0; n < (SBLOCKSIZE * SBCOUNT); n += 512) {
220 1.3 christos sb = (struct fs *)(void *)&buf[n];
221 1.3 christos if ((fstype = checkfstype()) == FSTYPE_NONE)
222 1.3 christos continue;
223 1.3 christos ufsmagic(n);
224 1.3 christos /* Update last potential FS SBs seen */
225 1.3 christos lastblk = blk + (n / 512);
226 1.3 christos (void)memcpy(lastmount, sb->fs_fsmnt, MAXMNTLEN);
227 1.1 xtraeme }
228 1.1 xtraeme }
229 1.2 kleink return EXIT_SUCCESS;
230 1.1 xtraeme }
231 1.1 xtraeme
232 1.1 xtraeme
233 1.1 xtraeme static void
234 1.1 xtraeme usage(void)
235 1.1 xtraeme {
236 1.1 xtraeme (void)fprintf(stderr,
237 1.3 christos "Usage: %s [-lv] [-s start] [-e end] device", getprogname());
238 1.2 kleink exit(EXIT_FAILURE);
239 1.1 xtraeme }
240 1.1 xtraeme
241 1.1 xtraeme
242 1.1 xtraeme int
243 1.1 xtraeme main(int argc, char **argv)
244 1.1 xtraeme {
245 1.1 xtraeme int ch, fd;
246 1.1 xtraeme daddr_t end = -1, beg = 0;
247 1.1 xtraeme struct disklabel dl;
248 1.1 xtraeme
249 1.1 xtraeme setprogname(argv[0]);
250 1.1 xtraeme
251 1.1 xtraeme while ((ch = getopt(argc, argv, "e:ls:v")) != -1)
252 1.1 xtraeme switch(ch) {
253 1.1 xtraeme case 'e':
254 1.1 xtraeme eflag = 1;
255 1.1 xtraeme end = atoi(optarg);
256 1.1 xtraeme break;
257 1.1 xtraeme case 'l':
258 1.1 xtraeme flags |= LABELS;
259 1.1 xtraeme break;
260 1.1 xtraeme case 's':
261 1.1 xtraeme beg = atoi(optarg);
262 1.1 xtraeme break;
263 1.1 xtraeme case 'v':
264 1.1 xtraeme flags |= VERBOSE;
265 1.1 xtraeme break;
266 1.1 xtraeme default:
267 1.1 xtraeme usage();
268 1.1 xtraeme /* NOTREACHED */
269 1.3 christos }
270 1.3 christos
271 1.1 xtraeme argc -= optind;
272 1.1 xtraeme argv += optind;
273 1.1 xtraeme
274 1.1 xtraeme if (argc != 1)
275 1.1 xtraeme usage();
276 1.1 xtraeme
277 1.1 xtraeme fd = opendisk(argv[0], O_RDONLY, device, sizeof(device), 0);
278 1.1 xtraeme
279 1.3 christos if (fd == -1)
280 1.3 christos err(1, "Cannot open `%s'", device);
281 1.1 xtraeme /* NOTREACHED */
282 1.1 xtraeme
283 1.3 christos if (ioctl(fd, DIOCGDINFO, &dl) == -1) {
284 1.3 christos warn("Couldn't retrieve disklabel");
285 1.3 christos (void)memset(&dl, 0, sizeof(dl));
286 1.3 christos dl.d_secperunit = 0x7fffffff;
287 1.3 christos } else {
288 1.1 xtraeme (void)printf("Disk: %s\n", dl.d_typename);
289 1.1 xtraeme (void)printf("Total sectors on disk: %" PRIu32 "\n\n",
290 1.3 christos dl.d_secperunit);
291 1.1 xtraeme }
292 1.1 xtraeme
293 1.1 xtraeme if (!eflag)
294 1.1 xtraeme end = dl.d_secperunit; /* default to max sectors */
295 1.1 xtraeme
296 1.3 christos return ufsscan(fd, beg, end, flags);
297 1.1 xtraeme }
298