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