xref: /original-bsd/old/dcheck/dcheck.c (revision 2301fdfb)
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 char copyright[] =
9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)dcheck.c	5.3 (Berkeley) 05/02/88";
15 #endif not lint
16 
17 /*
18  * dcheck - check directory consistency
19  */
20 #define	NB	10
21 #define	MAXNINDIR	(MAXBSIZE / sizeof (daddr_t))
22 
23 #include <sys/param.h>
24 #include <sys/inode.h>
25 #include <sys/fs.h>
26 #include <sys/dir.h>
27 #include <stdio.h>
28 
29 union {
30 	struct	fs fs;
31 	char pad[SBSIZE];
32 } fsun;
33 #define	sblock	fsun.fs
34 
35 struct dirstuff {
36 	int loc;
37 	struct dinode *ip;
38 	char dbuf[MAXBSIZE];
39 };
40 
41 struct	dinode	itab[MAXBSIZE / sizeof(struct dinode)];
42 struct	dinode	*gip;
43 ino_t	ilist[NB];
44 
45 int	fi;
46 ino_t	ino;
47 ino_t	*ecount;
48 int	headpr;
49 int	nfiles;
50 long	dev_bsize = 1;
51 
52 int	nerror;
53 daddr_t	bmap();
54 long	atol();
55 char	*malloc();
56 
57 main(argc, argv)
58 char *argv[];
59 {
60 	register i;
61 	long n;
62 
63 	while (--argc) {
64 		argv++;
65 		if (**argv=='-')
66 		switch ((*argv)[1]) {
67 
68 		case 'i':
69 			for(i=0; i<NB; i++) {
70 				n = atol(argv[1]);
71 				if(n == 0)
72 					break;
73 				ilist[i] = n;
74 				argv++;
75 				argc--;
76 			}
77 			ilist[i] = 0;
78 			continue;
79 
80 		default:
81 			printf("Bad flag %c\n", (*argv)[1]);
82 			nerror++;
83 		}
84 		check(*argv);
85 	}
86 	return(nerror);
87 }
88 
89 check(file)
90 char *file;
91 {
92 	register i, j, c;
93 
94 	fi = open(file, 0);
95 	if(fi < 0) {
96 		printf("cannot open %s\n", file);
97 		nerror++;
98 		return;
99 	}
100 	headpr = 0;
101 	printf("%s:\n", file);
102 	sync();
103 	bread(SBOFF, (char *)&sblock, SBSIZE);
104 	if (sblock.fs_magic != FS_MAGIC) {
105 		printf("%s: not a file system\n", file);
106 		nerror++;
107 		return;
108 	}
109 	dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
110 	nfiles = sblock.fs_ipg * sblock.fs_ncg;
111 	ecount = (ino_t *)malloc((nfiles+1) * sizeof (*ecount));
112 	if (ecount == 0) {
113 		printf("%s: not enough core for %d files\n", file, nfiles);
114 		exit(04);
115 	}
116 	for (i = 0; i<=nfiles; i++)
117 		ecount[i] = 0;
118 	ino = 0;
119 	for (c = 0; c < sblock.fs_ncg; c++) {
120 		for (i = 0;
121 		     i < sblock.fs_ipg / INOPF(&sblock);
122 		     i += sblock.fs_frag) {
123 			bread(fsbtodb(&sblock, cgimin(&sblock, c) + i),
124 			    (char *)itab, sblock.fs_bsize);
125 			for (j = 0; j < INOPB(&sblock); j++) {
126 				pass1(&itab[j]);
127 				ino++;
128 			}
129 		}
130 	}
131 	ino = 0;
132 	for (c = 0; c < sblock.fs_ncg; c++) {
133 		for (i = 0;
134 		     i < sblock.fs_ipg / INOPF(&sblock);
135 		     i += sblock.fs_frag) {
136 			bread(fsbtodb(&sblock, cgimin(&sblock, c) + i),
137 			    (char *)itab, sblock.fs_bsize);
138 			for (j = 0; j < INOPB(&sblock); j++) {
139 				pass2(&itab[j]);
140 				ino++;
141 			}
142 		}
143 	}
144 	free(ecount);
145 }
146 
147 pass1(ip)
148 	register struct dinode *ip;
149 {
150 	register struct direct *dp;
151 	struct dirstuff dirp;
152 	int k;
153 
154 	if((ip->di_mode&IFMT) != IFDIR)
155 		return;
156 	dirp.loc = 0;
157 	dirp.ip = ip;
158 	gip = ip;
159 	for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
160 		if(dp->d_ino == 0)
161 			continue;
162 		if(dp->d_ino > nfiles || dp->d_ino < ROOTINO) {
163 			printf("%d bad; %d/%s\n",
164 			    dp->d_ino, ino, dp->d_name);
165 			nerror++;
166 			continue;
167 		}
168 		for (k = 0; ilist[k] != 0; k++)
169 			if (ilist[k] == dp->d_ino) {
170 				printf("%d arg; %d/%s\n",
171 				     dp->d_ino, ino, dp->d_name);
172 				nerror++;
173 			}
174 		ecount[dp->d_ino]++;
175 	}
176 }
177 
178 pass2(ip)
179 register struct dinode *ip;
180 {
181 	register i;
182 
183 	i = ino;
184 	if ((ip->di_mode&IFMT)==0 && ecount[i]==0)
185 		return;
186 	if (ip->di_nlink==ecount[i] && ip->di_nlink!=0)
187 		return;
188 	if (headpr==0) {
189 		printf("     entries  link cnt\n");
190 		headpr++;
191 	}
192 	printf("%u\t%d\t%d\n", ino,
193 	    ecount[i], ip->di_nlink);
194 }
195 
196 /*
197  * get next entry in a directory.
198  */
199 struct direct *
200 readdir(dirp)
201 	register struct dirstuff *dirp;
202 {
203 	register struct direct *dp;
204 	daddr_t lbn, d;
205 
206 	for(;;) {
207 		if (dirp->loc >= dirp->ip->di_size)
208 			return NULL;
209 		if ((lbn = lblkno(&sblock, dirp->loc)) == 0) {
210 			d = bmap(lbn);
211 			if(d == 0)
212 				return NULL;
213 			bread(fsbtodb(&sblock, d), dirp->dbuf,
214 			    dblksize(&sblock, dirp->ip, lbn));
215 		}
216 		dp = (struct direct *)
217 		    (dirp->dbuf + blkoff(&sblock, dirp->loc));
218 		dirp->loc += dp->d_reclen;
219 		if (dp->d_ino == 0)
220 			continue;
221 		return (dp);
222 	}
223 }
224 
225 bread(bno, buf, cnt)
226 daddr_t bno;
227 char *buf;
228 {
229 	register i;
230 
231 	lseek(fi, bno * dev_bsize, 0);
232 	if (read(fi, buf, cnt) != cnt) {
233 		printf("read error %d\n", bno);
234 		for(i=0; i < cnt; i++)
235 			buf[i] = 0;
236 	}
237 }
238 
239 daddr_t
240 bmap(i)
241 {
242 	daddr_t ibuf[MAXNINDIR];
243 
244 	if(i < NDADDR)
245 		return(gip->di_db[i]);
246 	i -= NDADDR;
247 	if(i > NINDIR(&sblock)) {
248 		printf("%u - huge directory\n", ino);
249 		return((daddr_t)0);
250 	}
251 	bread(fsbtodb(&sblock, gip->di_ib[0]), (char *)ibuf, sizeof(ibuf));
252 	return(ibuf[i]);
253 }
254