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