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
main(argc,argv)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
check(file)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
pass1(ip)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
pass2(ip)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
pass3(ip)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 *
nreaddir(dirp)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
dotname(dp)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
pname(i,lev)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 *
lookup(i,ef)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
bread(bno,buf,lcount)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
bmap(bn)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