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