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