xref: /original-bsd/sbin/ncheck/ncheck.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[] = "@(#)ncheck.c	5.7 (Berkeley) 05/02/88";
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[MAXBSIZE/sizeof(struct dinode)];
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 		for (i = 0;
148 		     i < sblock.fs_ipg / INOPF(&sblock);
149 		     i += sblock.fs_frag) {
150 			bread(fsbtodb(&sblock, cgimin(&sblock, c) + i),
151 			    (char *)itab, sblock.fs_bsize);
152 			for (j = 0; j < INOPB(&sblock); j++) {
153 				if (itab[j].di_mode != 0)
154 					pass1(&itab[j]);
155 				ino++;
156 			}
157 		}
158 	}
159 	ilist[nxfile+1].ino = 0;
160 	ino = 0;
161 	for (c = 0; c < sblock.fs_ncg; c++) {
162 		for (i = 0;
163 		     i < sblock.fs_ipg / INOPF(&sblock);
164 		     i += sblock.fs_frag) {
165 			bread(fsbtodb(&sblock, cgimin(&sblock, c) + i),
166 			    (char *)itab, sblock.fs_bsize);
167 			for (j = 0; j < INOPB(&sblock); j++) {
168 				if (itab[j].di_mode != 0)
169 					pass2(&itab[j]);
170 				ino++;
171 			}
172 		}
173 	}
174 	ino = 0;
175 	for (c = 0; c < sblock.fs_ncg; c++) {
176 		for (i = 0;
177 		     i < sblock.fs_ipg / INOPF(&sblock);
178 		     i += sblock.fs_frag) {
179 			bread(fsbtodb(&sblock, cgimin(&sblock, c) + i),
180 			    (char *)itab, sblock.fs_bsize);
181 			for (j = 0; j < INOPB(&sblock); j++) {
182 				if (itab[j].di_mode != 0)
183 					pass3(&itab[j]);
184 				ino++;
185 			}
186 		}
187 	}
188 	close(fi);
189 	for (i = 0; i < hsize; i++)
190 		htab[i].h_ino = 0;
191 	for (i = iflg; i < NB; i++)
192 		ilist[i].ino = 0;
193 	nxfile = iflg;
194 }
195 
196 pass1(ip)
197 	register struct dinode *ip;
198 {
199 	int i;
200 
201 	if (mflg)
202 		for (i = 0; i < iflg; i++)
203 			if (ino == ilist[i].ino) {
204 				ilist[i].mode = ip->di_mode;
205 				ilist[i].uid = ip->di_uid;
206 				ilist[i].gid = ip->di_gid;
207 			}
208 	if ((ip->di_mode & IFMT) != IFDIR) {
209 		if (sflg==0 || nxfile>=NB)
210 			return;
211 		if ((ip->di_mode&IFMT)==IFBLK || (ip->di_mode&IFMT)==IFCHR
212 		  || ip->di_mode&(ISUID|ISGID)) {
213 			ilist[nxfile].ino = ino;
214 			ilist[nxfile].mode = ip->di_mode;
215 			ilist[nxfile].uid = ip->di_uid;
216 			ilist[nxfile++].gid = ip->di_gid;
217 			return;
218 		}
219 	}
220 	lookup(ino, 1);
221 }
222 
223 pass2(ip)
224 	register struct dinode *ip;
225 {
226 	register struct direct *dp;
227 	struct dirstuff dirp;
228 	struct htab *hp;
229 
230 	if((ip->di_mode&IFMT) != IFDIR)
231 		return;
232 	dirp.loc = 0;
233 	dirp.ip = ip;
234 	gip = ip;
235 	for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
236 		if(dp->d_ino == 0)
237 			continue;
238 		hp = lookup(dp->d_ino, 0);
239 		if(hp == 0)
240 			continue;
241 		if(dotname(dp))
242 			continue;
243 		hp->h_pino = ino;
244 		hp->h_name = &strngtab[strngloc];
245 		strngloc += strlen(dp->d_name) + 1;
246 		strcpy(hp->h_name, dp->d_name);
247 	}
248 }
249 
250 pass3(ip)
251 	register struct dinode *ip;
252 {
253 	register struct direct *dp;
254 	struct dirstuff dirp;
255 	int k;
256 
257 	if((ip->di_mode&IFMT) != IFDIR)
258 		return;
259 	dirp.loc = 0;
260 	dirp.ip = ip;
261 	gip = ip;
262 	for(dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
263 		if(aflg==0 && dotname(dp))
264 			continue;
265 		if(sflg == 0 && iflg == 0)
266 			goto pr;
267 		for(k = 0; ilist[k].ino != 0; k++)
268 			if(ilist[k].ino == dp->d_ino)
269 				break;
270 		if (ilist[k].ino == 0)
271 			continue;
272 		if (mflg)
273 			printf("mode %-6o uid %-5d gid %-5d ino ",
274 			    ilist[k].mode, ilist[k].uid, ilist[k].gid);
275 	pr:
276 		printf("%-5u\t", dp->d_ino);
277 		pname(ino, 0);
278 		printf("/%s", dp->d_name);
279 		if (lookup(dp->d_ino, 0))
280 			printf("/.");
281 		printf("\n");
282 	}
283 }
284 
285 /*
286  * get next entry in a directory.
287  */
288 struct direct *
289 readdir(dirp)
290 	register struct dirstuff *dirp;
291 {
292 	register struct direct *dp;
293 	daddr_t lbn, d;
294 
295 	for(;;) {
296 		if (dirp->loc >= dirp->ip->di_size)
297 			return NULL;
298 		if (blkoff(&sblock, dirp->loc) == 0) {
299 			lbn = lblkno(&sblock, dirp->loc);
300 			d = bmap(lbn);
301 			if(d == 0)
302 				return NULL;
303 			bread(fsbtodb(&sblock, d), dirp->dbuf,
304 			    dblksize(&sblock, dirp->ip, lbn));
305 		}
306 		dp = (struct direct *)
307 		    (dirp->dbuf + blkoff(&sblock, dirp->loc));
308 		dirp->loc += dp->d_reclen;
309 		if (dp->d_ino == 0)
310 			continue;
311 		return (dp);
312 	}
313 }
314 
315 dotname(dp)
316 	register struct direct *dp;
317 {
318 
319 	if (dp->d_name[0]=='.')
320 		if (dp->d_name[1]==0 ||
321 		   (dp->d_name[1]=='.' && dp->d_name[2]==0))
322 			return(1);
323 	return(0);
324 }
325 
326 pname(i, lev)
327 	ino_t i;
328 	int lev;
329 {
330 	register struct htab *hp;
331 
332 	if (i==ROOTINO)
333 		return;
334 	if ((hp = lookup(i, 0)) == 0) {
335 		printf("???");
336 		return;
337 	}
338 	if (lev > 10) {
339 		printf("...");
340 		return;
341 	}
342 	pname(hp->h_pino, ++lev);
343 	printf("/%s", hp->h_name);
344 }
345 
346 struct htab *
347 lookup(i, ef)
348 	ino_t i;
349 	int ef;
350 {
351 	register struct htab *hp;
352 
353 	for (hp = &htab[i%hsize]; hp->h_ino;) {
354 		if (hp->h_ino==i)
355 			return(hp);
356 		if (++hp >= &htab[hsize])
357 			hp = htab;
358 	}
359 	if (ef==0)
360 		return(0);
361 	if (++nhent >= hsize) {
362 		fprintf(stderr, "ncheck: hsize of %d is too small\n", hsize);
363 		exit(1);
364 	}
365 	hp->h_ino = i;
366 	return(hp);
367 }
368 
369 bread(bno, buf, cnt)
370 	daddr_t bno;
371 	char *buf;
372 	int cnt;
373 {
374 	register i;
375 
376 	lseek(fi, bno * dev_bsize, 0);
377 	if (read(fi, buf, cnt) != cnt) {
378 		fprintf(stderr, "ncheck: read error %d\n", bno);
379 		for(i=0; i < cnt; i++)
380 			buf[i] = 0;
381 	}
382 }
383 
384 /*
385  * Swiped from standalone sys.c.
386  */
387 #define	NBUFS	4
388 char	b[NBUFS][MAXBSIZE];
389 daddr_t	blknos[NBUFS];
390 
391 daddr_t
392 bmap(bn)
393 	register daddr_t bn;
394 {
395 	register int j;
396 	int i, sh;
397 	daddr_t nb, *bap;
398 
399 	if (bn < 0) {
400 		fprintf(stderr, "ncheck: bn %d negative\n", bn);
401 		return ((daddr_t)0);
402 	}
403 
404 	/*
405 	 * blocks 0..NDADDR are direct blocks
406 	 */
407 	if(bn < NDADDR)
408 		return(gip->di_db[bn]);
409 
410 	/*
411 	 * addresses NIADDR have single and double indirect blocks.
412 	 * the first step is to determine how many levels of indirection.
413 	 */
414 	sh = 1;
415 	bn -= NDADDR;
416 	for (j = NIADDR; j > 0; j--) {
417 		sh *= NINDIR(&sblock);
418 		if (bn < sh)
419 			break;
420 		bn -= sh;
421 	}
422 	if (j == 0) {
423 		printf("ncheck: bn %ld ovf, ino %u\n", bn, ino);
424 		return ((daddr_t)0);
425 	}
426 
427 	/*
428 	 * fetch the first indirect block address from the inode
429 	 */
430 	nb = gip->di_ib[NIADDR - j];
431 	if (nb == 0) {
432 		printf("ncheck: bn %ld void1, ino %u\n", bn, ino);
433 		return ((daddr_t)0);
434 	}
435 
436 	/*
437 	 * fetch through the indirect blocks
438 	 */
439 	for (; j <= NIADDR; j++) {
440 		if (blknos[j] != nb) {
441 			bread(fsbtodb(&sblock, nb), b[j], sblock.fs_bsize);
442 			blknos[j] = nb;
443 		}
444 		bap = (daddr_t *)b[j];
445 		sh /= NINDIR(&sblock);
446 		i = (bn / sh) % NINDIR(&sblock);
447 		nb = bap[i];
448 		if(nb == 0) {
449 			printf("ncheck: bn %ld void2, ino %u\n", bn, ino);
450 			return ((daddr_t)0);
451 		}
452 	}
453 	return (nb);
454 }
455