|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 12578 (0x3122) Types: TextFile Notes: UNIX file Names: »ncheck.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦f4b8d8c84⟧ UNIX Filesystem └─⟦this⟧ »cmd/ncheck.c«
/* * ncheck -- map an I-number into a pathname. * Also, look for special and setuid files. */ #include <stdio.h> #include <filsys.h> #include <fblk.h> #include <dir.h> #include <ino.h> #include <canon.h> #define NHASH 101 /* Prime provides a reasonable distribution */ #define NSBRK 512 /* Bytes to add each time out */ #define NFNAME 400 /* Longest filename generated */ #define NBPC 8 /* Bits per char (for bitmap) */ #define IBLK 12 /* I-node read blocking factor */ #define NINUM 20 /* Maximum number of i-numbers to look for */ #define ESEEN 0200 /* Seen bit for ENTRY */ #define unpack() l3tol(addrs, ip->di_addr, NADDR) /* Functions to test for directory or setuid/special i-numbers */ #define test(bm,i) (bm[(i)/NBPC] & 1<<((i)%NBPC)) #define mark(bm,i) (bm[(i)/NBPC] |= 1<<((i)%NBPC)) /* * Tables used by imap. * This effectively implements * the access polynomial for the indirect * blocks. */ #undef NI #define NI 1 #define NII 1 #define NIII 1 static daddr_t ranges[] = { ND, ND + (daddr_t)NI*NBN, ND + (daddr_t)NI*NBN + (daddr_t)NII*NBN*NBN, ND + (daddr_t)NI*NBN + (daddr_t)NII*NBN*NBN + (daddr_t)NIII*NBN*NBN*NBN, }; static char offsets[] = { 0, ND, ND+NI, ND+NI+NII, }; static daddr_t coeff[] = { 1, (daddr_t)NBN, (daddr_t)NBN*NBN, (daddr_t)NBN*NBN*NBN }; /* * Default filesystem names * to check. */ char *defnames[] = { "/dev/rrm00", NULL }; char tmi[] = "ncheck: too many i-numbers given\n"; char irderr[] = "ncheck: inode read error -- pass %d\n"; /* * An entry for each directory * name in the system containing * the current i-number and the * parent and the name. */ typedef struct ENTRY { struct ENTRY *e_next; ino_t e_pino; /* Parent i-number */ ino_t e_cino; /* Current i-number */ char e_name[]; /* Name */ } ENTRY; ENTRY *entries[NHASH]; /* Hashed entries */ char *dbmap; /* Directory I-node bit-map */ char *sbmap; /* Special + setuid i-node bitmap */ int ninumber; ino_t inums[NINUM]; char superb[BSIZE]; char ibuf[BSIZE*IBLK]; char dbuf[BSIZE]; char namebuf[NFNAME]; int aflag; /* All (print "." and ".." names) flag */ int sflag; /* Special and setuid files */ int uflag; /* Print unreferenced structure */ int exstat; /* Exit status */ int fsfd; /* File system file descriptor */ daddr_t fsize = SUPERI+1; /* Allow read of super-block */ ino_t isize; ino_t maxino; daddr_t imap(); char *malloc(); main(argc, argv) char *argv[]; { while (argc>1 && *argv[1]=='-') { switch (argv[1][1]) { case 'a': aflag = 1; break; case 'i': for (;;) { if (ninumber >= NINUM) { fprintf(stderr, tmi); exstat = 1; break; } if ((inums[ninumber] = atoi(argv[2])) == 0) break; argv++; argc--; ninumber++; } break; case 's': sflag = 1; break; case 'u': /* Unimplemented search for orphan structure */ uflag = 1; break; default: usage(); } argc--; argv++; } if (argc > 1) allcheck(argv+1); else allcheck(defnames); exit(exstat); } /* * Check the given list of filesystems */ allcheck(fsl) register char **fsl; { while (*fsl != NULL) ncheck(*fsl++); } /* * Do `ncheck' for each filesystem. */ ncheck(fsname) char *fsname; { register struct filsys *sbp; register unsigned nb; if ((fsfd = open(fsname, 0)) < 0) { fprintf(stderr, "%s: cannot open\n", fsname); exstat = 1; return; } printf( "%s:\n", fsname); sync(); bread((daddr_t)SUPERI, superb); sbp = superb; canshort(sbp->s_isize); candaddr(sbp->s_fsize); fsize = sbp->s_fsize; isize = sbp->s_isize; if (isize<INODEI+1 || isize>=fsize) cerr("Ridiculous fsize/isize"); maxino = (isize-INODEI) * INOPB; nb = (maxino+NBPC)/NBPC; if ((dbmap = malloc(nb)) == NULL) cerr("Out of memory for directory bit map"); bclear(dbmap, nb); if (sflag) { if ((sbmap = malloc(nb)) == NULL) cerr("Out of memory for special/setuid bit map"); bclear(sbmap, nb); } pass1(); pass2(); pass3(); mfree(); close(fsfd); } /* * Pass one consists of running down each * I-node and marking those that are directories. * This is used to tell which directory entries are * to be saved in the hash chains in pass 2. */ pass1() { register struct dinode *ip; register ino_t inum; register int i; register unsigned imax; size_t seek; inum = 1; seek = INODEI*BSIZE; for (i=maxino; i>0; i -= IBLK*INOPB) { lseek(fsfd, seek, 0); imax = i>IBLK*INOPB ? IBLK*INOPB : i; imax *= sizeof (struct dinode); seek += imax; if (read(fsfd, ibuf, imax) != imax) { fprintf(stderr, irderr, 1); exstat = 1; return; } for (ip = ibuf; ip < &ibuf[imax]; ip++) { canshort(ip->di_mode); canshort(ip->di_nlink); if ((ip->di_mode & IFMT) == IFDIR) mark(dbmap, inum); if (sflag && ip->di_mode&(ISUID|ISGID|IFBLK|IFCHR)) mark(sbmap, inum); inum++; } } } /* * Pass two scans the i-list looking for * all directories. For each directory * entry in each of these found, it * saves each name and i-number pair which * is itself a directory (as determined * by the bitmap computed in pass1). */ pass2() { register struct dinode *ip; register ino_t inum; register int i; register unsigned imax; size_t seek; inum = 1; seek = INODEI*BSIZE; for (i=maxino; i>0; i -= IBLK*INOPB) { lseek(fsfd, seek, 0); imax = i>IBLK*INOPB ? IBLK*INOPB : i; imax *= sizeof (struct dinode); seek += imax; if (read(fsfd, ibuf, imax) != imax) { fprintf(stderr, irderr, 2); exstat = 1; return; } for (ip = ibuf; ip < &ibuf[imax]; ip++) { canshort(ip->di_mode); canshort(ip->di_nlink); cansize(ip->di_size); if ((ip->di_mode & IFMT) == IFDIR) finddirs(ip, inum); inum++; } } } /* * Pass 3 uses the hashed table prodeuced * during pass1 and pass2 to generate * the output information that was * requested by the command line. */ pass3() { register struct dinode *ip; register ino_t inum; register int i; register unsigned imax; size_t seek; inum = 1; seek = INODEI*BSIZE; if (!sflag && (ninumber==0 || iarg(ROOTIN))) printf( "%u\t/.\n", ROOTIN); for (i=maxino; i>0; i -= IBLK*INOPB) { lseek(fsfd, seek, 0); imax = i>IBLK*INOPB ? IBLK*INOPB : i; imax *= sizeof (struct dinode); seek += imax; if (read(fsfd, ibuf, imax) != imax) { fprintf(stderr, irderr, 3); exstat = 1; return; } for (ip = ibuf; ip < &ibuf[imax]; ip++) { canshort(ip->di_mode); canshort(ip->di_nlink); cansize(ip->di_size); if ((ip->di_mode & IFMT) == IFDIR) printdir(ip, inum); inum++; } } } /* * Find all entries in this directory i-node * that are themselves directories. */ finddirs(ip, inum) register struct dinode *ip; register ino_t inum; { size_t size; daddr_t pb, bn; size = ip->di_size; bn = 0; while (size >= sizeof(struct direct)) { register struct direct *dp; if ((pb = imap(ip, bn++)) == 0) break; bread(pb, dbuf); for (dp=dbuf; dp < &dbuf[BSIZE]; dp++) { canino( dp->d_ino); if (dp->d_ino) { if (dp->d_ino > maxino) dirline(inum, dp, "bad"); else if (test(dbmap, dp->d_ino)) direnter(dp, inum); } size -= sizeof( struct direct); if (size == 0) break; } } } /* * Print all of the names found * in this directory. */ printdir(ip, ino) register struct dinode *ip; register ino_t ino; { size_t size; daddr_t pb, bn; size = ip->di_size; bn = 0; while (size >= sizeof(struct direct)) { register struct direct *dp; if ((pb = imap(ip, bn++)) == 0) break; bread(pb, dbuf); for (dp=dbuf; dp < &dbuf[BSIZE]; dp++) { canino( dp->d_ino); if (dp->d_ino) { if (dp->d_ino > maxino) continue; if (sflag && !test(sbmap, dp->d_ino)) continue; if (ninumber!=0 && !iarg(dp->d_ino)) continue; outname(dp, ino); } size -= sizeof( struct direct); if (size == 0) break; } } } /* * Print out the actual name by * traversing the structures * for a directory entry. */ outname(dp, ino) register struct direct *dp; ino_t ino; { register char *np; np = dp->d_name; if (!aflag && *np++=='.') if ((*np=='.' && np[1]=='\0') || *np=='\0') return; np = &namebuf[NFNAME]; *--np = '\0'; if (!aflag && test(dbmap, dp->d_ino)) { *--np = '.'; *--np = '/'; } { register char *cp; for (cp = dp->d_name; cp < &dp->d_name[DIRSIZ]; cp++) if (*cp == '\0') break; while (cp > dp->d_name) *--np = *--cp; *--np = '/'; } outpart(np, ino, dp->d_ino); } /* * Put out each name part. * Either get to the root * or find no parent. * `ep' is the pointer running * backwards in the namebuf. */ outpart(np, ino, oino) register char *np; ino_t ino; ino_t oino; { register ENTRY *ep; register char *cp; register int found = 0; register char *snp; if (ino != ROOTIN) { for (ep = entries[ino%NHASH]; ep != NULL; ep = ep->e_next) if (ep->e_cino == ino) { if (ep->e_name[0] & ESEEN) { *--np = '.'; *--np = '.'; *--np = '.'; return; } snp = np; cp = &ep->e_name[strlen(ep->e_name)]; while (cp > ep->e_name) *--np = *--cp; *--np = '/'; ep->e_name[0] |= ESEEN; found = 1; if (np > namebuf+DIRSIZ) outpart(np, ep->e_pino, oino); ep->e_name[0] &= ~ESEEN; np = snp; } if (!found) { *--np = '?'; *--np = '?'; } } if (!found || ino==ROOTIN) printf( "%u\t%s\n", oino, np); } /* * Enter a directory entry and the current * i-number into the chained hash table * for use by pass 3. */ direnter(dp, ino) register struct direct *dp; ino_t ino; { register ENTRY *ep; register char *cp; register int n; cp = dp->d_name; if (*cp++ == '.') if ((*cp=='.' && cp[1]=='\0') || *cp=='\0') return; for (cp = dp->d_name; *cp != '\0'; cp++) if (cp >= &dp->d_name[DIRSIZ]) break; n = cp - dp->d_name; if ((ep = (ENTRY *)malloc(n+sizeof(char)+sizeof(ENTRY))) == NULL) cerr("Out of memory for directory entries"); ep->e_pino = ino; ep->e_cino = dp->d_ino; strncpy(ep->e_name, dp->d_name, n); ep->e_name[n] = '\0'; /* * Compute hash and store in entries table. */ n = ep->e_cino%NHASH; ep->e_next = entries[n]; entries[n] = ep; } /* * Return true if the argument * i-node is the one of the `-i' * arguments. */ iarg(ino) register ino_t ino; { register int i; for (i=0; i<ninumber; i++) if (inums[i] == ino) return (1); return (0); } /* * Print out a line for a directory * that is found in the search (e.g. * bad or argument directories). */ dirline(ino, dp, str) ino_t ino; register struct direct *dp; char *str; { printf("%u %s: %u/%-*.*s\n", dp->d_ino, str, ino, DIRSIZ, DIRSIZ, dp->d_name); } /* * For a given inode (`ip'), * map a logical block number (`bn') * onto a physical disc block number. */ daddr_t imap(ip, lb) register struct dinode *ip; daddr_t lb; { register il; daddr_t bpos, pb; register daddr_t *bp; register daddr_t addrs[NADDR]; unpack(); for (il=0; il<4; il++) if (lb < ranges[il]) { if (il != 0) lb -= ranges[il-1]; bpos = lb/coeff[il]; lb %= coeff[il]; bp = &addrs[(int)bpos + offsets[il]]; if ((pb = *bp) != 0) { /* * Map through indirect * blocks here. */ while (il-- > 0) { bread(pb, dbuf); bpos = lb/coeff[il]; lb %= coeff[il]; bp = (daddr_t *)dbuf + bpos; if ((pb = *bp) == 0) break; pb = *bp; candaddr( pb); } } return (pb); } return (0); } /* * Read the specified block number * into `buf'. */ bread(bn, buf) daddr_t bn; char *buf; { if (bn >= fsize) { badblock(bn); bclear(buf, BSIZE); return; } lseek(fsfd, (size_t)BSIZE * bn, 0); if (read(fsfd, buf, BSIZE) != BSIZE) { fprintf(stderr, "ncheck: Read error %D\n", (long)bn); exstat = 1; bclear(buf, BSIZE); } } /* * Clear a block of memory * pointed to by `bp' for size * `nb' bytes. */ bclear(bp, nb) register char *bp; register unsigned nb; { if (nb) do { *bp++ = 0; } while (--nb); } /* * free scratch memory * Space used to check a filesystem is freed. This includes bitmaps * and directory entries. */ mfree( ) { register ENTRY *ep, **epp; for (epp=entries; epp<&entries[NHASH]; ) { for (ep= *epp; ep; ep=ep->e_next) free( (char *)ep); *epp++ = NULL; } free( dbmap); if (sbmap) free( sbmap); } /* * Error routines */ badblock(bn) daddr_t bn; { fprintf(stderr, "ncheck: bad block #%D\n", (long)bn); exstat = 1; } /* * Unrecoverable errors */ cerr(x) { fprintf(stderr, "ncheck: %r\n", &x); exit(1); } usage() { fprintf(stderr, "Usage: ncheck [-a] [-s] [-i ino ...] [filesystem ...]"); }