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