xref: /original-bsd/sbin/icheck/icheck.c (revision c3e32dec)
1 /*-
2  * Copyright (c) 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1988, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)icheck.c	8.1 (Berkeley) 06/05/93";
16 #endif /* not lint */
17 
18 /*
19  * icheck
20  */
21 #define	NB	500
22 #define	MAXFN	500
23 #define	MAXNINDIR	(MAXBSIZE / sizeof (daddr_t))
24 
25 #include <sys/param.h>
26 #include <sys/time.h>
27 #include <ufs/ufs/dinode.h>
28 #include <ufs/ffs/fs.h>
29 #ifndef STANDALONE
30 #include <unistd.h>
31 #include <stdio.h>
32 #endif
33 
34 union {
35 	struct	fs sb;
36 	char pad[SBSIZE];
37 } sbun;
38 #define	sblock sbun.sb
39 
40 union {
41 	struct	cg cg;
42 	char pad[MAXBSIZE];
43 } cgun;
44 #define	cgrp cgun.cg
45 
46 struct dinode itab[MAXBSIZE / sizeof(struct dinode)];
47 
48 daddr_t	blist[NB];
49 daddr_t	fsblist[NB];
50 char	*bmap;
51 
52 int	mflg;
53 int	dflg;
54 int	fi;
55 ino_t	ino;
56 int	cginit;
57 
58 ino_t	nrfile;
59 ino_t	ndfile;
60 ino_t	nbfile;
61 ino_t	ncfile;
62 ino_t	nlfile;
63 ino_t	nsfile;
64 
65 daddr_t	nblock;
66 daddr_t	nfrag;
67 daddr_t	nindir;
68 daddr_t	niindir;
69 
70 daddr_t	nffree;
71 daddr_t	nbfree;
72 
73 daddr_t	ndup;
74 
75 int	nerror;
76 long	dev_bsize = 1;
77 
78 int	bread __P((daddr_t, char *, ssize_t));
79 long	atol();
80 #ifndef STANDALONE
81 char	*malloc();
82 char	*calloc();
83 #endif
84 
85 main(argc, argv)
86 	int argc;
87 	char *argv[];
88 {
89 	register i;
90 	long n;
91 
92 	blist[0] = -1;
93 #ifndef STANDALONE
94 	while (--argc) {
95 		argv++;
96 		if (**argv=='-')
97 		switch ((*argv)[1]) {
98 		case 'd':
99 			dflg++;
100 			continue;
101 
102 		case 'm':
103 			mflg++;
104 			continue;
105 
106 		case 'b':
107 			for(i=0; i<NB && argc >= 2; i++) {
108 				n = atol(argv[1]);
109 				if(n == 0)
110 					break;
111 				blist[i] = n;
112 				argv++;
113 				argc--;
114 			}
115 			blist[i] = -1;
116 			continue;
117 
118 		default:
119 			printf("Bad flag\n");
120 		}
121 		check(*argv);
122 	}
123 #else
124 	{
125 		static char fname[128];
126 
127 		printf("File: ");
128 		gets(fname);
129 		check(fname);
130 	}
131 #endif
132 	return(nerror);
133 }
134 
135 check(file)
136 	char *file;
137 {
138 	register i, j, c;
139 	daddr_t d, cgd, cbase, b;
140 	long n;
141 	char buf[BUFSIZ];
142 
143 	fi = open(file, 0);
144 	if (fi < 0) {
145 		perror(file);
146 		nerror |= 04;
147 		return;
148 	}
149 	printf("%s:\n", file);
150 	nrfile = 0;
151 	ndfile = 0;
152 	ncfile = 0;
153 	nbfile = 0;
154 	nlfile = 0;
155 	nsfile = 0;
156 
157 	nblock = 0;
158 	nfrag = 0;
159 	nindir = 0;
160 	niindir = 0;
161 
162 	ndup = 0;
163 #ifndef STANDALONE
164 	sync();
165 #endif
166 	getsb(&sblock, file);
167 	if (nerror)
168 		return;
169 	for (n=0; blist[n] != -1; n++)
170 		fsblist[n] = dbtofsb(&sblock, blist[n]);
171 	ino = 0;
172 	n = roundup(howmany(sblock.fs_size, NBBY), sizeof(short));
173 #ifdef STANDALONE
174 	bmap = NULL;
175 #else
176 	bmap = malloc((unsigned)n);
177 #endif
178 	if (bmap==NULL) {
179 		printf("Not enough core; duplicates unchecked\n");
180 		dflg++;
181 	}
182 	ino = 0;
183 	cginit = 1;
184 	if (!dflg) {
185 		for (i = 0; i < (unsigned)n; i++)
186 			bmap[i] = 0;
187 		for (c = 0; c < sblock.fs_ncg; c++) {
188 			cgd = cgtod(&sblock, c);
189 			if (c == 0)
190 				d = cgbase(&sblock, c);
191 			else
192 				d = cgsblock(&sblock, c);
193 			(void)sprintf(buf, "spare super block %d", c);
194 			for (; d < cgd; d += sblock.fs_frag)
195 				chk(d, buf, sblock.fs_bsize);
196 			d = cgimin(&sblock, c);
197 			(void)sprintf(buf, "cylinder group %d", c);
198 			while (cgd < d) {
199 				chk(cgd, buf, sblock.fs_bsize);
200 				cgd += sblock.fs_frag;
201 			}
202 			d = cgdmin(&sblock, c);
203 			i = INOPB(&sblock);
204 			for (; cgd < d; cgd += sblock.fs_frag) {
205 				(void)sprintf(buf, "inodes %d-%d", ino, ino + i);
206 				chk(cgd, buf, sblock.fs_bsize);
207 				ino += i;
208 			}
209 			if (c == 0) {
210 				d += howmany(sblock.fs_cssize, sblock.fs_fsize);
211 				for (; cgd < d; cgd++)
212 					chk(cgd, "csum", sblock.fs_fsize);
213 			}
214 		}
215 	}
216 	ino = 0;
217 	cginit = 0;
218 	for (c = 0; c < sblock.fs_ncg; c++) {
219 		for (i = 0;
220 		     i < sblock.fs_ipg / INOPF(&sblock);
221 		     i += sblock.fs_frag) {
222 			bread(fsbtodb(&sblock, cgimin(&sblock, c) + i),
223 			    (char *)itab, sblock.fs_bsize);
224 			for (j = 0; j < INOPB(&sblock); j++) {
225 				pass1(&itab[j]);
226 				ino++;
227 			}
228 		}
229 	}
230 	ino = 0;
231 #ifndef STANDALONE
232 	sync();
233 #endif
234 	nffree = 0;
235 	nbfree = 0;
236 	for (c = 0; c < sblock.fs_ncg; c++) {
237 		cbase = cgbase(&sblock, c);
238 		bread(fsbtodb(&sblock, cgtod(&sblock, c)), (char *)&cgrp,
239 			sblock.fs_cgsize);
240 		if (!cg_chkmagic(&cgrp))
241 			printf("cg %d: bad magic number\n", c);
242 		for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) {
243 			if (isblock(&sblock, cg_blksfree(&cgrp),
244 			    b / sblock.fs_frag)) {
245 				nbfree++;
246 				chk(cbase+b, "free block", sblock.fs_bsize);
247 			} else {
248 				for (d = 0; d < sblock.fs_frag; d++)
249 					if (isset(cg_blksfree(&cgrp), b+d)) {
250 						chk(cbase+b+d, "free frag", sblock.fs_fsize);
251 						nffree++;
252 					}
253 			}
254 		}
255 	}
256 	close(fi);
257 #ifndef STANDALONE
258 	if (bmap)
259 		free(bmap);
260 #endif
261 
262 	i = nrfile + ndfile + ncfile + nbfile + nlfile + nsfile;
263 #ifndef STANDALONE
264 	printf("files %6u (r=%u,d=%u,b=%u,c=%u,sl=%u,sock=%u)\n",
265 		i, nrfile, ndfile, nbfile, ncfile, nlfile, nsfile);
266 #else
267 	printf("files %u (r=%u,d=%u,b=%u,c=%u,sl=%u,sock=%u)\n",
268 		i, nrfile, ndfile, nbfile, ncfile, nlfile, nsfile);
269 #endif
270 	n = (nblock + nindir + niindir) * sblock.fs_frag + nfrag;
271 #ifdef STANDALONE
272 	printf("used %ld (i=%ld,ii=%ld,b=%ld,f=%ld)\n",
273 		n, nindir, niindir, nblock, nfrag);
274 	printf("free %ld (b=%ld,f=%ld)\n", nffree + sblock.fs_frag * nbfree,
275 	    nbfree, nffree);
276 #else
277 	printf("used %7ld (i=%ld,ii=%ld,b=%ld,f=%ld)\n",
278 		n, nindir, niindir, nblock, nfrag);
279 	printf("free %7ld (b=%ld,f=%ld)\n", nffree + sblock.fs_frag * nbfree,
280 	    nbfree, nffree);
281 #endif
282 	if(!dflg) {
283 		n = 0;
284 		for (d = 0; d < sblock.fs_size; d++)
285 			if(!duped(d, sblock.fs_fsize)) {
286 				if(mflg)
287 					printf("%ld missing\n", d);
288 				n++;
289 			}
290 		printf("missing%5ld\n", n);
291 	}
292 }
293 
294 pass1(ip)
295 	register struct dinode *ip;
296 {
297 	daddr_t ind1[MAXNINDIR];
298 	daddr_t ind2[MAXNINDIR];
299 	daddr_t db, ib;
300 	register int i, j, k, siz;
301 	int lbn;
302 	char buf[BUFSIZ];
303 
304 	i = ip->di_mode & IFMT;
305 	if(i == 0)
306 		return;
307 	switch (i) {
308 	case IFCHR:
309 		ncfile++;
310 		return;
311 	case IFBLK:
312 		nbfile++;
313 		return;
314 	case IFDIR:
315 		ndfile++;
316 		break;
317 	case IFREG:
318 		nrfile++;
319 		break;
320 	case IFSOCK:
321 		nsfile++;
322 		break;
323 	case IFLNK:
324 		nlfile++;
325 		break;
326 	default:
327 		printf("bad mode %u\n", ino);
328 		return;
329 	}
330 	for (i = 0; i < NDADDR; i++) {
331 		db = ip->di_db[i];
332 		if (db == 0)
333 			continue;
334 		siz = dblksize(&sblock, ip, i);
335 		(void)sprintf(buf, "logical data block %d", i);
336 		chk(db, buf, siz);
337 		if (siz == sblock.fs_bsize)
338 			nblock++;
339 		else
340 			nfrag += howmany(siz, sblock.fs_fsize);
341 	}
342 	for(i = 0; i < NIADDR; i++) {
343 		ib = ip->di_ib[i];
344 		if (ib == 0)
345 			continue;
346 		if (chk(ib, "1st indirect", sblock.fs_bsize))
347 			continue;
348 		bread(fsbtodb(&sblock, ib), (char *)ind1, sblock.fs_bsize);
349 		nindir++;
350 		for (j = 0; j < NINDIR(&sblock); j++) {
351 			ib = ind1[j];
352 			if (ib == 0)
353 				continue;
354 			if (i == 0) {
355 				lbn = NDADDR + j;
356 				siz = dblksize(&sblock, ip, lbn);
357 				(void)sprintf(buf, "logical data block %d", lbn);
358 				chk(ib, buf, siz);
359 				if (siz == sblock.fs_bsize)
360 					nblock++;
361 				else
362 					nfrag += howmany(siz, sblock.fs_fsize);
363 				continue;
364 			}
365 			if (chk(ib, "2nd indirect", sblock.fs_bsize))
366 				continue;
367 			bread(fsbtodb(&sblock, ib), (char *)ind2,
368 				sblock.fs_bsize);
369 			niindir++;
370 			for (k = 0; k < NINDIR(&sblock); k++) {
371 				ib = ind2[k];
372 				if (ib == 0)
373 					continue;
374 				lbn = NDADDR + NINDIR(&sblock) * (i + j) + k;
375 				siz = dblksize(&sblock, ip, lbn);
376 				(void)sprintf(buf, "logical data block %d", lbn);
377 				chk(ib, buf, siz);
378 				if (siz == sblock.fs_bsize)
379 					nblock++;
380 				else
381 					nfrag += howmany(siz, sblock.fs_fsize);
382 			}
383 		}
384 	}
385 }
386 
387 chk(bno, s, size)
388 	daddr_t bno;
389 	char *s;
390 	int size;
391 {
392 	register n, cg;
393 	int frags;
394 
395 	cg = dtog(&sblock, bno);
396 	if (cginit == 0 && bno >= sblock.fs_frag * sblock.fs_size) {
397 		printf("%ld bad; inode=%u, class=%s\n", bno, ino, s);
398 		return(1);
399 	}
400 	frags = numfrags(&sblock, size);
401 	if (frags == sblock.fs_frag) {
402 		if (duped(bno, size)) {
403 			printf("%ld dup block; inode=%u, class=%s\n",
404 			    bno, ino, s);
405 			ndup += sblock.fs_frag;
406 		}
407 	} else {
408 		for (n = 0; n < frags; n++) {
409 			if (duped(bno + n, sblock.fs_fsize)) {
410 				printf("%ld dup frag; inode=%u, class=%s\n",
411 				    bno, ino, s);
412 				ndup++;
413 			}
414 		}
415 	}
416 	for (n=0; blist[n] != -1; n++)
417 		if (fsblist[n] >= bno && fsblist[n] < bno + frags)
418 			printf("%ld arg; frag %d of %d, inode=%u, class=%s\n",
419 				blist[n], fsblist[n] - bno, frags, ino, s);
420 	return(0);
421 }
422 
423 duped(bno, size)
424 	daddr_t bno;
425 	int size;
426 {
427 	if(dflg)
428 		return(0);
429 	if (size != sblock.fs_fsize && size != sblock.fs_bsize)
430 		printf("bad size %d to duped\n", size);
431 	if (size == sblock.fs_fsize) {
432 		if (isset(bmap, bno))
433 			return(1);
434 		setbit(bmap, bno);
435 		return (0);
436 	}
437 	if (bno % sblock.fs_frag != 0)
438 		printf("bad bno %d to duped\n", bno);
439 	if (isblock(&sblock, bmap, bno/sblock.fs_frag))
440 		return (1);
441 	setblock(&sblock, bmap, bno/sblock.fs_frag);
442 	return(0);
443 }
444 
445 getsb(fs, file)
446 	register struct fs *fs;
447 	char *file;
448 {
449 	int i, j, size;
450 
451 	if (bread(SBOFF, (char *)fs, SBSIZE)) {
452 		printf("bad super block");
453 		perror(file);
454 		nerror |= 04;
455 		return;
456 	}
457 	if (fs->fs_magic != FS_MAGIC) {
458 		printf("%s: bad magic number\n", file);
459 		nerror |= 04;
460 		return;
461 	}
462 	dev_bsize = fs->fs_fsize / fsbtodb(fs, 1);
463 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
464 		size = sblock.fs_cssize - i < sblock.fs_bsize ?
465 		    sblock.fs_cssize - i : sblock.fs_bsize;
466 		sblock.fs_csp[j] = (struct csum *)calloc(1, size);
467 		bread(fsbtodb(fs, fs->fs_csaddr + (j * fs->fs_frag)),
468 		      (char *)fs->fs_csp[j], size);
469 	}
470 }
471 
472 bread(bno, buf, cnt)
473 	daddr_t bno;
474 	char *buf;
475 	ssize_t cnt;
476 {
477 	register i;
478 
479 	lseek(fi, (off_t)bno * dev_bsize, SEEK_SET);
480 	if ((i = read(fi, buf, cnt)) != cnt) {
481 		for (i = 0; i < sblock.fs_bsize; i++)
482 			buf[i] = 0;
483 		return (1);
484 	}
485 	return (0);
486 }
487 
488 /*
489  * check if a block is available
490  */
491 isblock(fs, cp, h)
492 	struct fs *fs;
493 	unsigned char *cp;
494 	int h;
495 {
496 	unsigned char mask;
497 
498 	switch (fs->fs_frag) {
499 	case 8:
500 		return (cp[h] == 0xff);
501 	case 4:
502 		mask = 0x0f << ((h & 0x1) << 2);
503 		return ((cp[h >> 1] & mask) == mask);
504 	case 2:
505 		mask = 0x03 << ((h & 0x3) << 1);
506 		return ((cp[h >> 2] & mask) == mask);
507 	case 1:
508 		mask = 0x01 << (h & 0x7);
509 		return ((cp[h >> 3] & mask) == mask);
510 	default:
511 #ifdef STANDALONE
512 		printf("isblock bad fs_frag %d\n", fs->fs_frag);
513 #else
514 		fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
515 #endif
516 		return;
517 	}
518 }
519 
520 /*
521  * put a block into the map
522  */
523 setblock(fs, cp, h)
524 	struct fs *fs;
525 	unsigned char *cp;
526 	int h;
527 {
528 	switch (fs->fs_frag) {
529 	case 8:
530 		cp[h] = 0xff;
531 		return;
532 	case 4:
533 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
534 		return;
535 	case 2:
536 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
537 		return;
538 	case 1:
539 		cp[h >> 3] |= (0x01 << (h & 0x7));
540 		return;
541 	default:
542 #ifdef STANDALONE
543 		printf("setblock bad fs_frag %d\n", fs->fs_frag);
544 #else
545 		fprintf(stderr, "setblock bad fs_frag %d\n", fs->fs_frag);
546 #endif
547 		return;
548 	}
549 }
550