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