|
|
1.1 root 1: /*
2: * ncheck -- map an I-number into a pathname.
3: * Also, look for special and setuid files.
4: */
5:
6: #include <stdio.h>
7: #include <sys/filsys.h>
8: #include <sys/fblk.h>
9: #include <sys/dir.h>
10: #include <sys/ino.h>
11: #include <canon.h>
12:
13: #define NHASH 101 /* Prime provides a reasonable distribution */
14: #define NSBRK 512 /* Bytes to add each time out */
15: #define NFNAME 400 /* Longest filename generated */
16: #define NBPC 8 /* Bits per char (for bitmap) */
17: #define IBLK 12 /* I-node read blocking factor */
18: #define NINUM 20 /* Maximum number of i-numbers to look for */
19: #define ESEEN 0200 /* Seen bit for ENTRY */
20: #define unpack() l3tol(addrs, ip->di_addr, NADDR)
21:
22: /* Functions to test for directory or setuid/special i-numbers */
23: #define test(bm,i) (bm[(i)/NBPC] & 1<<((i)%NBPC))
24: #define mark(bm,i) (bm[(i)/NBPC] |= 1<<((i)%NBPC))
25:
26: /*
27: * Tables used by imap.
28: * This effectively implements
29: * the access polynomial for the indirect
30: * blocks.
31: */
32: #undef NI
33: #define NI 1
34: #define NII 1
35: #define NIII 1
36: static daddr_t ranges[] = {
37: ND,
38: ND + (daddr_t)NI*NBN,
39: ND + (daddr_t)NI*NBN + (daddr_t)NII*NBN*NBN,
40: ND + (daddr_t)NI*NBN + (daddr_t)NII*NBN*NBN + (daddr_t)NIII*NBN*NBN*NBN,
41: };
42:
43: static char offsets[] = {
44: 0,
45: ND,
46: ND+NI,
47: ND+NI+NII,
48: };
49:
50: static daddr_t coeff[] = {
51: 1, (daddr_t)NBN, (daddr_t)NBN*NBN, (daddr_t)NBN*NBN*NBN
52: };
53:
54: /*
55: * Default filesystem names
56: * to check.
57: */
58: char *defnames[] = {
59: "/dev/rrm00",
60: NULL
61: };
62:
63: char tmi[] = "ncheck: too many i-numbers given\n";
64: char irderr[] = "ncheck: inode read error -- pass %d\n";
65:
66: /*
67: * An entry for each directory
68: * name in the system containing
69: * the current i-number and the
70: * parent and the name.
71: */
72: typedef struct ENTRY {
73: struct ENTRY *e_next;
74: ino_t e_pino; /* Parent i-number */
75: ino_t e_cino; /* Current i-number */
76: char e_name[]; /* Name */
77: } ENTRY;
78:
79: ENTRY *entries[NHASH]; /* Hashed entries */
80:
81: char *dbmap; /* Directory I-node bit-map */
82: char *sbmap; /* Special + setuid i-node bitmap */
83:
84: int ninumber;
85: ino_t inums[NINUM];
86: char superb[BSIZE];
87: char ibuf[BSIZE*IBLK];
88: char dbuf[BSIZE];
89: char namebuf[NFNAME];
90:
91: int aflag; /* All (print "." and ".." names) flag */
92: int sflag; /* Special and setuid files */
93: int uflag; /* Print unreferenced structure */
94: int exstat; /* Exit status */
95: int fsfd; /* File system file descriptor */
96: daddr_t fsize = SUPERI+1; /* Allow read of super-block */
97: ino_t isize;
98: ino_t maxino;
99:
100: daddr_t imap();
101: char *malloc();
102:
103: main(argc, argv)
104: char *argv[];
105: {
106:
107: while (argc>1 && *argv[1]=='-') {
108: switch (argv[1][1]) {
109: case 'a':
110: aflag = 1;
111: break;
112:
113: case 'i':
114: for (;;) {
115: if (ninumber >= NINUM) {
116: fprintf(stderr, tmi);
117: exstat = 1;
118: break;
119: }
120: if ((inums[ninumber] = atoi(argv[2])) == 0)
121: break;
122: argv++;
123: argc--;
124: ninumber++;
125: }
126: break;
127:
128: case 's':
129: sflag = 1;
130: break;
131:
132: case 'u': /* Unimplemented search for orphan structure */
133: uflag = 1;
134: break;
135:
136: default:
137: usage();
138: }
139: argc--;
140: argv++;
141: }
142: if (argc > 1)
143: allcheck(argv+1); else
144: allcheck(defnames);
145: exit(exstat);
146: }
147:
148: /*
149: * Check the given list of filesystems
150: */
151: allcheck(fsl)
152: register char **fsl;
153: {
154: while (*fsl != NULL)
155: ncheck(*fsl++);
156: }
157:
158: /*
159: * Do `ncheck' for each filesystem.
160: */
161: ncheck(fsname)
162: char *fsname;
163: {
164: register struct filsys *sbp;
165: register unsigned nb;
166:
167: if ((fsfd = open(fsname, 0)) < 0) {
168: fprintf(stderr, "%s: cannot open\n", fsname);
169: exstat = 1;
170: return;
171: }
172: printf( "%s:\n", fsname);
173: sync();
174: bread((daddr_t)SUPERI, superb);
175: sbp = superb;
176:
177: canshort(sbp->s_isize);
178: candaddr(sbp->s_fsize);
179:
180: fsize = sbp->s_fsize;
181: isize = sbp->s_isize;
182: if (isize<INODEI+1 || isize>=fsize)
183: cerr("Ridiculous fsize/isize");
184: maxino = (isize-INODEI) * INOPB;
185: nb = (maxino+NBPC)/NBPC;
186: if ((dbmap = malloc(nb)) == NULL)
187: cerr("Out of memory for directory bit map");
188: bclear(dbmap, nb);
189: if (sflag) {
190: if ((sbmap = malloc(nb)) == NULL)
191: cerr("Out of memory for special/setuid bit map");
192: bclear(sbmap, nb);
193: }
194: pass1();
195: pass2();
196: pass3();
197: mfree();
198: close(fsfd);
199: }
200:
201: /*
202: * Pass one consists of running down each
203: * I-node and marking those that are directories.
204: * This is used to tell which directory entries are
205: * to be saved in the hash chains in pass 2.
206: */
207: pass1()
208: {
209: register struct dinode *ip;
210: register ino_t inum;
211: register int i;
212: register unsigned imax;
213: fsize_t seek;
214:
215: inum = 1;
216: seek = INODEI*BSIZE;
217: for (i=maxino; i>0; i -= IBLK*INOPB) {
218: lseek(fsfd, seek, 0);
219: imax = i>IBLK*INOPB ? IBLK*INOPB : i;
220: imax *= sizeof (struct dinode);
221: seek += imax;
222: if (read(fsfd, ibuf, imax) != imax) {
223: fprintf(stderr, irderr, 1);
224: exstat = 1;
225: return;
226: }
227: for (ip = ibuf; ip < &ibuf[imax]; ip++) {
228: canshort(ip->di_mode);
229: canshort(ip->di_nlink);
230: if ((ip->di_mode & IFMT) == IFDIR)
231: mark(dbmap, inum);
232: if (sflag && ip->di_mode&(ISUID|ISGID|IFBLK|IFCHR))
233: mark(sbmap, inum);
234: inum++;
235: }
236: }
237: }
238:
239: /*
240: * Pass two scans the i-list looking for
241: * all directories. For each directory
242: * entry in each of these found, it
243: * saves each name and i-number pair which
244: * is itself a directory (as determined
245: * by the bitmap computed in pass1).
246: */
247: pass2()
248: {
249: register struct dinode *ip;
250: register ino_t inum;
251: register int i;
252: register unsigned imax;
253: fsize_t seek;
254:
255: inum = 1;
256: seek = INODEI*BSIZE;
257: for (i=maxino; i>0; i -= IBLK*INOPB) {
258: lseek(fsfd, seek, 0);
259: imax = i>IBLK*INOPB ? IBLK*INOPB : i;
260: imax *= sizeof (struct dinode);
261: seek += imax;
262: if (read(fsfd, ibuf, imax) != imax) {
263: fprintf(stderr, irderr, 2);
264: exstat = 1;
265: return;
266: }
267: for (ip = ibuf; ip < &ibuf[imax]; ip++) {
268: canshort(ip->di_mode);
269: canshort(ip->di_nlink);
270: cansize(ip->di_size);
271: if ((ip->di_mode & IFMT) == IFDIR)
272: finddirs(ip, inum);
273: inum++;
274: }
275: }
276: }
277:
278: /*
279: * Pass 3 uses the hashed table prodeuced
280: * during pass1 and pass2 to generate
281: * the output information that was
282: * requested by the command line.
283: */
284: pass3()
285: {
286: register struct dinode *ip;
287: register ino_t inum;
288: register int i;
289: register unsigned imax;
290: fsize_t seek;
291:
292: inum = 1;
293: seek = INODEI*BSIZE;
294: if (!sflag && (ninumber==0 || iarg(ROOTIN)))
295: printf( "%u\t/.\n", ROOTIN);
296: for (i=maxino; i>0; i -= IBLK*INOPB) {
297: lseek(fsfd, seek, 0);
298: imax = i>IBLK*INOPB ? IBLK*INOPB : i;
299: imax *= sizeof (struct dinode);
300: seek += imax;
301: if (read(fsfd, ibuf, imax) != imax) {
302: fprintf(stderr, irderr, 3);
303: exstat = 1;
304: return;
305: }
306: for (ip = ibuf; ip < &ibuf[imax]; ip++) {
307: canshort(ip->di_mode);
308: canshort(ip->di_nlink);
309: cansize(ip->di_size);
310: if ((ip->di_mode & IFMT) == IFDIR)
311: printdir(ip, inum);
312: inum++;
313: }
314: }
315: }
316:
317: /*
318: * Find all entries in this directory i-node
319: * that are themselves directories.
320: */
321: finddirs(ip, inum)
322: register struct dinode *ip;
323: register ino_t inum;
324: {
325: fsize_t size;
326: daddr_t pb, bn;
327:
328: size = ip->di_size;
329: bn = 0;
330: while (size >= sizeof(struct direct)) {
331: register struct direct *dp;
332:
333: if ((pb = imap(ip, bn++)) == 0)
334: break;
335: bread(pb, dbuf);
336: for (dp=dbuf; dp < &dbuf[BSIZE]; dp++) {
337: canino( dp->d_ino);
338: if (dp->d_ino) {
339: if (dp->d_ino > maxino)
340: dirline(inum, dp, "bad");
341: else if (test(dbmap, dp->d_ino))
342: direnter(dp, inum);
343: }
344: size -= sizeof( struct direct);
345: if (size == 0)
346: break;
347: }
348: }
349: }
350:
351: /*
352: * Print all of the names found
353: * in this directory.
354: */
355: printdir(ip, ino)
356: register struct dinode *ip;
357: register ino_t ino;
358: {
359: fsize_t size;
360: daddr_t pb, bn;
361:
362: size = ip->di_size;
363: bn = 0;
364: while (size >= sizeof(struct direct)) {
365: register struct direct *dp;
366:
367: if ((pb = imap(ip, bn++)) == 0)
368: break;
369: bread(pb, dbuf);
370: for (dp=dbuf; dp < &dbuf[BSIZE]; dp++) {
371: canino( dp->d_ino);
372: if (dp->d_ino) {
373: if (dp->d_ino > maxino)
374: continue;
375: if (sflag && !test(sbmap, dp->d_ino))
376: continue;
377: if (ninumber!=0 && !iarg(dp->d_ino))
378: continue;
379: outname(dp, ino);
380: }
381: size -= sizeof( struct direct);
382: if (size == 0)
383: break;
384: }
385: }
386: }
387:
388: /*
389: * Print out the actual name by
390: * traversing the structures
391: * for a directory entry.
392: */
393: outname(dp, ino)
394: register struct direct *dp;
395: ino_t ino;
396: {
397: register char *np;
398:
399: np = dp->d_name;
400: if (!aflag && *np++=='.')
401: if ((*np=='.' && np[1]=='\0') || *np=='\0')
402: return;
403: np = &namebuf[NFNAME];
404: *--np = '\0';
405: if (!aflag && test(dbmap, dp->d_ino)) {
406: *--np = '.';
407: *--np = '/';
408: }
409: {
410: register char *cp;
411:
412: for (cp = dp->d_name; cp < &dp->d_name[DIRSIZ]; cp++)
413: if (*cp == '\0')
414: break;
415: while (cp > dp->d_name)
416: *--np = *--cp;
417: *--np = '/';
418: }
419: outpart(np, ino, dp->d_ino);
420: }
421:
422: /*
423: * Put out each name part.
424: * Either get to the root
425: * or find no parent.
426: * `ep' is the pointer running
427: * backwards in the namebuf.
428: */
429: outpart(np, ino, oino)
430: register char *np;
431: ino_t ino;
432: ino_t oino;
433: {
434: register ENTRY *ep;
435: register char *cp;
436: register int found = 0;
437: register char *snp;
438:
439: if (ino != ROOTIN) {
440: for (ep = entries[ino%NHASH]; ep != NULL; ep = ep->e_next)
441: if (ep->e_cino == ino) {
442: if (ep->e_name[0] & ESEEN) {
443: *--np = '.';
444: *--np = '.';
445: *--np = '.';
446: return;
447: }
448: snp = np;
449: cp = &ep->e_name[strlen(ep->e_name)];
450: while (cp > ep->e_name)
451: *--np = *--cp;
452: *--np = '/';
453: ep->e_name[0] |= ESEEN;
454: found = 1;
455: if (np > namebuf+DIRSIZ)
456: outpart(np, ep->e_pino, oino);
457: ep->e_name[0] &= ~ESEEN;
458: np = snp;
459: }
460: if (!found) {
461: *--np = '?';
462: *--np = '?';
463: }
464: }
465: if (!found || ino==ROOTIN)
466: printf( "%u\t%s\n", oino, np);
467: }
468:
469: /*
470: * Enter a directory entry and the current
471: * i-number into the chained hash table
472: * for use by pass 3.
473: */
474: direnter(dp, ino)
475: register struct direct *dp;
476: ino_t ino;
477: {
478: register ENTRY *ep;
479: register char *cp;
480: register int n;
481:
482: cp = dp->d_name;
483: if (*cp++ == '.')
484: if ((*cp=='.' && cp[1]=='\0') || *cp=='\0')
485: return;
486: for (cp = dp->d_name; *cp != '\0'; cp++)
487: if (cp >= &dp->d_name[DIRSIZ])
488: break;
489: n = cp - dp->d_name;
490: if ((ep = (ENTRY *)malloc(n+sizeof(char)+sizeof(ENTRY))) == NULL)
491: cerr("Out of memory for directory entries");
492: ep->e_pino = ino;
493: ep->e_cino = dp->d_ino;
494: strncpy(ep->e_name, dp->d_name, n);
495: ep->e_name[n] = '\0';
496: /*
497: * Compute hash and store in entries table.
498: */
499: n = ep->e_cino%NHASH;
500: ep->e_next = entries[n];
501: entries[n] = ep;
502: }
503:
504: /*
505: * Return true if the argument
506: * i-node is the one of the `-i'
507: * arguments.
508: */
509: iarg(ino)
510: register ino_t ino;
511: {
512: register int i;
513:
514: for (i=0; i<ninumber; i++)
515: if (inums[i] == ino)
516: return (1);
517: return (0);
518: }
519:
520: /*
521: * Print out a line for a directory
522: * that is found in the search (e.g.
523: * bad or argument directories).
524: */
525: dirline(ino, dp, str)
526: ino_t ino;
527: register struct direct *dp;
528: char *str;
529: {
530: printf("%u %s: %u/%-*.*s\n", dp->d_ino, str, ino,
531: DIRSIZ, DIRSIZ, dp->d_name);
532: }
533:
534: /*
535: * For a given inode (`ip'),
536: * map a logical block number (`bn')
537: * onto a physical disc block number.
538: */
539: daddr_t
540: imap(ip, lb)
541: register struct dinode *ip;
542: daddr_t lb;
543: {
544: register il;
545: daddr_t bpos, pb;
546: register daddr_t *bp;
547: register daddr_t addrs[NADDR];
548:
549: unpack();
550: for (il=0; il<4; il++)
551: if (lb < ranges[il]) {
552: if (il != 0)
553: lb -= ranges[il-1];
554: bpos = lb/coeff[il];
555: lb %= coeff[il];
556: bp = &addrs[(int)bpos + offsets[il]];
557: if ((pb = *bp) != 0) {
558: /*
559: * Map through indirect
560: * blocks here.
561: */
562: while (il-- > 0) {
563: bread(pb, dbuf);
564: bpos = lb/coeff[il];
565: lb %= coeff[il];
566: bp = (daddr_t *)dbuf + bpos;
567: if ((pb = *bp) == 0)
568: break;
569: pb = *bp;
570: candaddr( pb);
571: }
572: }
573: return (pb);
574: }
575: return (0);
576: }
577:
578: /*
579: * Read the specified block number
580: * into `buf'.
581: */
582: bread(bn, buf)
583: daddr_t bn;
584: char *buf;
585: {
586: if (bn >= fsize) {
587: badblock(bn);
588: bclear(buf, BSIZE);
589: return;
590: }
591: lseek(fsfd, (fsize_t)BSIZE * bn, 0);
592: if (read(fsfd, buf, BSIZE) != BSIZE) {
593: fprintf(stderr, "ncheck: Read error %ld\n", (long)bn);
594: exstat = 1;
595: bclear(buf, BSIZE);
596: }
597: }
598:
599: /*
600: * Clear a block of memory
601: * pointed to by `bp' for size
602: * `nb' bytes.
603: */
604: bclear(bp, nb)
605: register char *bp;
606: register unsigned nb;
607: {
608: if (nb)
609: do {
610: *bp++ = 0;
611: } while (--nb);
612: }
613:
614: /*
615: * free scratch memory
616: * Space used to check a filesystem is freed. This includes bitmaps
617: * and directory entries.
618: */
619: mfree( )
620: {
621: register ENTRY *ep,
622: **epp;
623:
624: for (epp=entries; epp<&entries[NHASH]; ) {
625: for (ep= *epp; ep; ep=ep->e_next)
626: free( (char *)ep);
627: *epp++ = NULL;
628: }
629: free( dbmap);
630: if (sbmap)
631: free( sbmap);
632: }
633:
634: /*
635: * Error routines
636: */
637: badblock(bn)
638: daddr_t bn;
639: {
640: fprintf(stderr, "ncheck: bad block #%ld\n", (long)bn);
641: exstat = 1;
642: }
643:
644: /*
645: * Unrecoverable errors
646: */
647: cerr(x)
648: {
649: fprintf(stderr, "ncheck: %r\n", &x);
650: exit(1);
651: }
652:
653: usage()
654: {
655: fprintf(stderr, "Usage: ncheck [-a] [-s] [-i ino ...] [filesystem ...]");
656: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.