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