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