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