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