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