xref: /csrg-svn/sbin/ncheck/ncheck.c (revision 30558)
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[] = "@(#)ncheck.c	5.6 (Berkeley) 02/23/87";
15 #endif not lint
16 
17 /*
18  * ncheck -- obtain file names from reading filesystem
19  */
20 
21 #define	NB		500
22 #define	MAXNINDIR	(MAXBSIZE / sizeof (daddr_t))
23 
24 #include <sys/param.h>
25 #include <sys/inode.h>
26 #include <sys/fs.h>
27 #include <sys/dir.h>
28 #include <stdio.h>
29 
30 struct	fs	sblock;
31 struct	dinode	itab[MAXIPG];
32 struct 	dinode	*gip;
33 struct ilist {
34 	ino_t	ino;
35 	u_short	mode;
36 	short	uid;
37 	short	gid;
38 } ilist[NB];
39 struct	htab
40 {
41 	ino_t	h_ino;
42 	ino_t	h_pino;
43 	char	*h_name;
44 } *htab;
45 char *strngtab;
46 long hsize;
47 int strngloc;
48 
49 struct dirstuff {
50 	int loc;
51 	struct dinode *ip;
52 	char dbuf[MAXBSIZE];
53 };
54 
55 int	aflg;
56 int	sflg;
57 int	iflg; /* number of inodes being searched for */
58 int	mflg;
59 int	fi;
60 ino_t	ino;
61 int	nhent;
62 int	nxfile;
63 long	dev_bsize = 1;
64 
65 int	nerror;
66 daddr_t	bmap();
67 long	atol();
68 struct htab *lookup();
69 
70 main(argc, argv)
71 	int argc;
72 	char *argv[];
73 {
74 	register i;
75 	long n;
76 
77 	while (--argc) {
78 		argv++;
79 		if (**argv=='-')
80 		switch ((*argv)[1]) {
81 
82 		case 'a':
83 			aflg++;
84 			continue;
85 
86 		case 'i':
87 			for(iflg=0; iflg<NB; iflg++) {
88 				n = atol(argv[1]);
89 				if(n == 0)
90 					break;
91 				ilist[iflg].ino = n;
92 				nxfile = iflg;
93 				argv++;
94 				argc--;
95 			}
96 			continue;
97 
98 		case 'm':
99 			mflg++;
100 			continue;
101 
102 		case 's':
103 			sflg++;
104 			continue;
105 
106 		default:
107 			fprintf(stderr, "ncheck: bad flag %c\n", (*argv)[1]);
108 			nerror++;
109 		}
110 		check(*argv);
111 	}
112 	return(nerror);
113 }
114 
115 check(file)
116 	char *file;
117 {
118 	register int i, j, c;
119 	int nfiles;
120 
121 	fi = open(file, 0);
122 	if(fi < 0) {
123 		fprintf(stderr, "ncheck: cannot open %s\n", file);
124 		nerror++;
125 		return;
126 	}
127 	nhent = 0;
128 	printf("%s:\n", file);
129 	sync();
130 	bread(SBOFF, (char *)&sblock, SBSIZE);
131 	if (sblock.fs_magic != FS_MAGIC) {
132 		printf("%s: not a file system\n", file);
133 		nerror++;
134 		return;
135 	}
136 	dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
137 	hsize = sblock.fs_ipg * sblock.fs_ncg - sblock.fs_cstotal.cs_nifree + 1;
138 	htab = (struct htab *)malloc(hsize * sizeof(struct htab));
139 	strngtab = (char *)malloc(30 * hsize);
140 	if (htab == 0 || strngtab == 0) {
141 		printf("not enough memory to allocate tables\n");
142 		nerror++;
143 		return;
144 	}
145 	ino = 0;
146 	for (c = 0; c < sblock.fs_ncg; c++) {
147 		bread(fsbtodb(&sblock, cgimin(&sblock, c)), (char *)itab,
148 		    sblock.fs_ipg * sizeof (struct dinode));
149 		for(j = 0; j < sblock.fs_ipg; j++) {
150 			if (itab[j].di_mode != 0)
151 				pass1(&itab[j]);
152 			ino++;
153 		}
154 	}
155 	ilist[nxfile+1].ino = 0;
156 	ino = 0;
157 	for (c = 0; c < sblock.fs_ncg; c++) {
158 		bread(fsbtodb(&sblock, cgimin(&sblock, c)), (char *)itab,
159 		    sblock.fs_ipg * sizeof (struct dinode));
160 		for(j = 0; j < sblock.fs_ipg; j++) {
161 			if (itab[j].di_mode != 0)
162 				pass2(&itab[j]);
163 			ino++;
164 		}
165 	}
166 	ino = 0;
167 	for (c = 0; c < sblock.fs_ncg; c++) {
168 		bread(fsbtodb(&sblock, cgimin(&sblock, c)), (char *)itab,
169 		    sblock.fs_ipg * sizeof (struct dinode));
170 		for(j = 0; j < sblock.fs_ipg; j++) {
171 			if (itab[j].di_mode != 0)
172 				pass3(&itab[j]);
173 			ino++;
174 		}
175 	}
176 	close(fi);
177 	for (i = 0; i < hsize; i++)
178 		htab[i].h_ino = 0;
179 	for (i = iflg; i < NB; i++)
180 		ilist[i].ino = 0;
181 	nxfile = iflg;
182 }
183 
184 pass1(ip)
185 	register struct dinode *ip;
186 {
187 	int i;
188 
189 	if (mflg)
190 		for (i = 0; i < iflg; i++)
191 			if (ino == ilist[i].ino) {
192 				ilist[i].mode = ip->di_mode;
193 				ilist[i].uid = ip->di_uid;
194 				ilist[i].gid = ip->di_gid;
195 			}
196 	if ((ip->di_mode & IFMT) != IFDIR) {
197 		if (sflg==0 || nxfile>=NB)
198 			return;
199 		if ((ip->di_mode&IFMT)==IFBLK || (ip->di_mode&IFMT)==IFCHR
200 		  || ip->di_mode&(ISUID|ISGID)) {
201 			ilist[nxfile].ino = ino;
202 			ilist[nxfile].mode = ip->di_mode;
203 			ilist[nxfile].uid = ip->di_uid;
204 			ilist[nxfile++].gid = ip->di_gid;
205 			return;
206 		}
207 	}
208 	lookup(ino, 1);
209 }
210 
211 pass2(ip)
212 	register struct dinode *ip;
213 {
214 	register struct direct *dp;
215 	struct dirstuff dirp;
216 	struct htab *hp;
217 
218 	if((ip->di_mode&IFMT) != IFDIR)
219 		return;
220 	dirp.loc = 0;
221 	dirp.ip = ip;
222 	gip = ip;
223 	for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
224 		if(dp->d_ino == 0)
225 			continue;
226 		hp = lookup(dp->d_ino, 0);
227 		if(hp == 0)
228 			continue;
229 		if(dotname(dp))
230 			continue;
231 		hp->h_pino = ino;
232 		hp->h_name = &strngtab[strngloc];
233 		strngloc += strlen(dp->d_name) + 1;
234 		strcpy(hp->h_name, dp->d_name);
235 	}
236 }
237 
238 pass3(ip)
239 	register struct dinode *ip;
240 {
241 	register struct direct *dp;
242 	struct dirstuff dirp;
243 	int k;
244 
245 	if((ip->di_mode&IFMT) != IFDIR)
246 		return;
247 	dirp.loc = 0;
248 	dirp.ip = ip;
249 	gip = ip;
250 	for(dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
251 		if(aflg==0 && dotname(dp))
252 			continue;
253 		if(sflg == 0 && iflg == 0)
254 			goto pr;
255 		for(k = 0; ilist[k].ino != 0; k++)
256 			if(ilist[k].ino == dp->d_ino)
257 				break;
258 		if (ilist[k].ino == 0)
259 			continue;
260 		if (mflg)
261 			printf("mode %-6o uid %-5d gid %-5d ino ",
262 			    ilist[k].mode, ilist[k].uid, ilist[k].gid);
263 	pr:
264 		printf("%-5u\t", dp->d_ino);
265 		pname(ino, 0);
266 		printf("/%s", dp->d_name);
267 		if (lookup(dp->d_ino, 0))
268 			printf("/.");
269 		printf("\n");
270 	}
271 }
272 
273 /*
274  * get next entry in a directory.
275  */
276 struct direct *
277 readdir(dirp)
278 	register struct dirstuff *dirp;
279 {
280 	register struct direct *dp;
281 	daddr_t lbn, d;
282 
283 	for(;;) {
284 		if (dirp->loc >= dirp->ip->di_size)
285 			return NULL;
286 		if (blkoff(&sblock, dirp->loc) == 0) {
287 			lbn = lblkno(&sblock, dirp->loc);
288 			d = bmap(lbn);
289 			if(d == 0)
290 				return NULL;
291 			bread(fsbtodb(&sblock, d), dirp->dbuf,
292 			    dblksize(&sblock, dirp->ip, lbn));
293 		}
294 		dp = (struct direct *)
295 		    (dirp->dbuf + blkoff(&sblock, dirp->loc));
296 		dirp->loc += dp->d_reclen;
297 		if (dp->d_ino == 0)
298 			continue;
299 		return (dp);
300 	}
301 }
302 
303 dotname(dp)
304 	register struct direct *dp;
305 {
306 
307 	if (dp->d_name[0]=='.')
308 		if (dp->d_name[1]==0 ||
309 		   (dp->d_name[1]=='.' && dp->d_name[2]==0))
310 			return(1);
311 	return(0);
312 }
313 
314 pname(i, lev)
315 	ino_t i;
316 	int lev;
317 {
318 	register struct htab *hp;
319 
320 	if (i==ROOTINO)
321 		return;
322 	if ((hp = lookup(i, 0)) == 0) {
323 		printf("???");
324 		return;
325 	}
326 	if (lev > 10) {
327 		printf("...");
328 		return;
329 	}
330 	pname(hp->h_pino, ++lev);
331 	printf("/%s", hp->h_name);
332 }
333 
334 struct htab *
335 lookup(i, ef)
336 	ino_t i;
337 	int ef;
338 {
339 	register struct htab *hp;
340 
341 	for (hp = &htab[i%hsize]; hp->h_ino;) {
342 		if (hp->h_ino==i)
343 			return(hp);
344 		if (++hp >= &htab[hsize])
345 			hp = htab;
346 	}
347 	if (ef==0)
348 		return(0);
349 	if (++nhent >= hsize) {
350 		fprintf(stderr, "ncheck: hsize of %d is too small\n", hsize);
351 		exit(1);
352 	}
353 	hp->h_ino = i;
354 	return(hp);
355 }
356 
357 bread(bno, buf, cnt)
358 	daddr_t bno;
359 	char *buf;
360 	int cnt;
361 {
362 	register i;
363 
364 	lseek(fi, bno * dev_bsize, 0);
365 	if (read(fi, buf, cnt) != cnt) {
366 		fprintf(stderr, "ncheck: read error %d\n", bno);
367 		for(i=0; i < cnt; i++)
368 			buf[i] = 0;
369 	}
370 }
371 
372 /*
373  * Swiped from standalone sys.c.
374  */
375 #define	NBUFS	4
376 char	b[NBUFS][MAXBSIZE];
377 daddr_t	blknos[NBUFS];
378 
379 daddr_t
380 bmap(bn)
381 	register daddr_t bn;
382 {
383 	register int j;
384 	int i, sh;
385 	daddr_t nb, *bap;
386 
387 	if (bn < 0) {
388 		fprintf(stderr, "ncheck: bn %d negative\n", bn);
389 		return ((daddr_t)0);
390 	}
391 
392 	/*
393 	 * blocks 0..NDADDR are direct blocks
394 	 */
395 	if(bn < NDADDR)
396 		return(gip->di_db[bn]);
397 
398 	/*
399 	 * addresses NIADDR have single and double indirect blocks.
400 	 * the first step is to determine how many levels of indirection.
401 	 */
402 	sh = 1;
403 	bn -= NDADDR;
404 	for (j = NIADDR; j > 0; j--) {
405 		sh *= NINDIR(&sblock);
406 		if (bn < sh)
407 			break;
408 		bn -= sh;
409 	}
410 	if (j == 0) {
411 		printf("ncheck: bn %ld ovf, ino %u\n", bn, ino);
412 		return ((daddr_t)0);
413 	}
414 
415 	/*
416 	 * fetch the first indirect block address from the inode
417 	 */
418 	nb = gip->di_ib[NIADDR - j];
419 	if (nb == 0) {
420 		printf("ncheck: bn %ld void1, ino %u\n", bn, ino);
421 		return ((daddr_t)0);
422 	}
423 
424 	/*
425 	 * fetch through the indirect blocks
426 	 */
427 	for (; j <= NIADDR; j++) {
428 		if (blknos[j] != nb) {
429 			bread(fsbtodb(&sblock, nb), b[j], sblock.fs_bsize);
430 			blknos[j] = nb;
431 		}
432 		bap = (daddr_t *)b[j];
433 		sh /= NINDIR(&sblock);
434 		i = (bn / sh) % NINDIR(&sblock);
435 		nb = bap[i];
436 		if(nb == 0) {
437 			printf("ncheck: bn %ld void2, ino %u\n", bn, ino);
438 			return ((daddr_t)0);
439 		}
440 	}
441 	return (nb);
442 }
443