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