scan_ffs.c revision 1.1 1 /* $NetBSD: scan_ffs.c,v 1.1 2005/06/15 18:06:19 xtraeme 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.1 2005/06/15 18:06:19 xtraeme 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 static const char *fstype = NULL;
73
74 static int eflag = 0;
75 static int flags = 0;
76
77 static daddr_t blk, lastblk;
78
79 static struct fs *sb;
80
81 static int
82 checkfstype(void)
83 {
84 switch (sb->fs_magic) {
85 case FS_UFS1_MAGIC:
86 case FS_UFS1_MAGIC_SWAPPED:
87 sb->fs_size = sb->fs_old_size;
88 fstype = "FFSv1";
89 return 1;
90 case FS_UFS2_MAGIC:
91 case FS_UFS2_MAGIC_SWAPPED:
92 fstype = "FFSv2";
93 return 2;
94 default:
95 return -1;
96 }
97 }
98
99 static void
100 printpart(int flag, int ffsize, int n)
101 {
102
103 int fsrv = checkfstype();
104
105 if (flag == VERBOSE) {
106 (void)printf("block: %" PRIu64" "
107 "id %x,%x size %" PRIu64"\n",
108 blk + (n / 512), sb->fs_id[0],
109 sb->fs_id[1], sb->fs_size);
110 } else if (flag == LABELS) {
111 (void)printf("X: %9" PRIu64 "",
112 (uint64_t)((off_t)sb->fs_size * sb->fs_fsize / 512));
113 if (fsrv == 1) /* FFSv1 */
114 (void)printf(" %9" PRIu64 "",
115 blk + (n / 512)-(2 * SBLOCKSIZE / 512));
116 else if (fsrv == 2) /* FFSv2 */
117 (void)printf(" %9" PRIu64 "",
118 blk + (n / 512)-(ffsize * SBLOCKSIZE / 512 + 128));
119 (void)printf(" 4.2BSD %6d %5d%4d # %s [%s]\n",
120 sb->fs_fsize, sb->fs_bsize,
121 sb->fs_old_cpg, lastmount, fstype);
122 } else {
123 printf("%s ", fstype);
124 if (fsrv == 1) /* FFSv1 */
125 (void)printf("at %" PRIu64 "",
126 blk + (n / 512) - (2 * SBLOCKSIZE / 512));
127 else if (fsrv == 2) /* FFSv2 */
128 (void)printf("at %" PRIu64 "",
129 blk + (n / 512) - (ffsize * SBLOCKSIZE / 512 + 128));
130 (void)printf(" size %" PRIu64 ", last mounted on %s\n",
131 (uint64_t)((off_t)sb->fs_size * sb->fs_fsize / 512),
132 lastmount);
133 }
134 }
135
136 static void
137 ufsmagic(int n)
138 {
139 int fsrv = checkfstype();
140
141 /*
142 * FIXME:
143 * It cannot find FFSv1 partitions with fsize/bsize > 2048/16384,
144 * same problem found in the original program that comes from
145 * OpenBSD (scan_ffs(1)).
146 */
147 if (flags & VERBOSE)
148 printpart(VERBOSE, NADA, n);
149 if (fsrv == 1) { /* FFSv1 */
150 if (((blk + (n / 512)) - lastblk) == (SBLOCKSIZE / 512)) {
151 if (flags & LABELS)
152 printpart(LABELS, NADA, n);
153 else
154 printpart(NADA, NADA, n);
155 }
156 } else if (fsrv == 2) { /* FFSv2 */
157 /*
158 * That checks for FFSv2 partitions with fragsize/blocksize:
159 * 512/4096, 1024/8192, 2048/16384, 4096/32768 and 8192/65536.
160 * Really enough for now.
161 */
162 if (((blk + (n / 512)) - lastblk) == (SBLOCKSIZE / 512)) {
163 if (flags & LABELS)
164 printpart(LABELS, 1, n);
165 else
166 printpart(NADA, 1, n);
167 } else if (((blk + (n / 512)) - lastblk) == (2 * SBLOCKSIZE / 512)) {
168 if (flags & LABELS)
169 printpart(LABELS, 2, n);
170 else
171 printpart(NADA, 2, n);
172 } else if (((blk + (n / 512)) - lastblk) == (4 * SBLOCKSIZE / 512)) {
173 if (flags & LABELS)
174 printpart(LABELS, 4, n);
175 else
176 printpart(NADA, 4, n);
177 } else if (((blk + (n / 512)) - lastblk) == (8 * SBLOCKSIZE / 512)) {
178 if (flags & LABELS)
179 printpart(LABELS, 8, n);
180 else
181 printpart(NADA, 8, n);
182 }
183 }
184 }
185
186 static int
187 ufsscan(int fd, daddr_t beg, daddr_t end, int fflags)
188 {
189
190 u_int8_t buf[SBLOCKSIZE * SBCOUNT];
191 int n, fsrv;
192
193 lastblk = -1;
194 memset(lastmount, 0, MAXMNTLEN);
195
196 if (fflags & LABELS)
197 (void)printf("# size offset fstype [fsize bsize cpg]\n");
198
199 for (blk = beg; blk <= ((end < 0) ? blk: end);
200 blk += (SBCOUNT * SBLOCKSIZE / 512)) {
201 memset(buf, 0, sizeof(buf));
202
203 if (lseek(fd, (off_t)blk * 512, SEEK_SET) < 0)
204 err(1, "lseek");
205 /* NOTREACHED */
206
207 if (read(fd, buf, sizeof(buf)) < 0)
208 err(1, "read");
209 /* NOTREACHED */
210
211 for (n = 0; n < (SBLOCKSIZE * SBCOUNT); n += 512) {
212 sb = (struct fs*)(&buf[n]);
213 fsrv = checkfstype();
214
215 if (fsrv >= 1) { /* found! */
216 ufsmagic(n);
217 /* Update last potential FS SBs seen */
218 lastblk = blk + (n / 512);
219 memcpy(lastmount, sb->fs_fsmnt, MAXMNTLEN);
220 }
221 }
222 }
223 return 0;
224 }
225
226
227 static void
228 usage(void)
229 {
230 (void)fprintf(stderr,
231 "usage: %s [-lv] [-s start] [-e end] device", getprogname());
232 exit(1);
233 }
234
235
236 int
237 main(int argc, char **argv)
238 {
239 int ch, fd;
240 daddr_t end = -1, beg = 0;
241 struct disklabel dl;
242
243 setprogname(argv[0]);
244
245 while ((ch = getopt(argc, argv, "e:ls:v")) != -1)
246 switch(ch) {
247 case 'e':
248 eflag = 1;
249 end = atoi(optarg);
250 break;
251 case 'l':
252 flags |= LABELS;
253 break;
254 case 's':
255 beg = atoi(optarg);
256 break;
257 case 'v':
258 flags |= VERBOSE;
259 break;
260 default:
261 usage();
262 /* NOTREACHED */
263 }
264 argc -= optind;
265 argv += optind;
266
267 if (argc != 1)
268 usage();
269
270 fd = opendisk(argv[0], O_RDONLY, device, sizeof(device), 0);
271
272 if (fd < 0)
273 err(1, "%s", device);
274 /* NOTREACHED */
275
276 if (ioctl(fd, DIOCGDINFO, &dl) == -1)
277 warn("couldn't retrieve disklabel.\n");
278 else {
279 (void)printf("Disk: %s\n", dl.d_typename);
280 (void)printf("Total sectors on disk: %" PRIu32 "\n\n",
281 dl.d_secperunit);
282 }
283
284 if (!eflag)
285 end = dl.d_secperunit; /* default to max sectors */
286
287 return (ufsscan(fd, beg, end, flags));
288 }
289