/* @(#)fsdb.c 1.3 */ /* fsdb - file system debugger */ #if u370 || u3b #define loword(X) (((ushort *)&X)[1]) #define lobyte(X) (((char *)&X)[1]) #endif #ifdef STANDALONE #define FsTYPE 2 #endif #include "sys/param.h" #include "signal.h" #include "sys/types.h" #include "sys/sysmacros.h" #include "sys/inode.h" #include "sys/dir.h" #include "sys/ino.h" #include "stdio.h" #include "setjmp.h" #include "sys/filsys.h" #ifdef STANDALONE #define ASSEM "Stand-Alone" #else #define ASSEM "UNIX T/S" #endif #define NBUF 3 #define MODE 0 #define LINK 2 #define UID 4 #define GID 6 #define SZ 8 #define INOSZ (BSIZE/64) #define ADRMSK (BSIZE -1) #define A0 12 #define MIN 12 #define MAJ 13 #define AT 52 #define MT 56 #define CT 60 #define NUMB 10 #define INODE 11 #define BLOCK 12 #define DIR 13 #define HIBIT 0100000 #ifdef pdp11 #define SLOC BSIZE + 2 #else #define SLOC BSIZE + 4 #endif struct buf { struct buf *fwd; struct buf *back; char *blkaddr; short valid; long blkno; } buf[NBUF], bhdr; char buffers[NBUF][BSIZE]; struct dir { short inumb; char nm[DIRSIZ]; } *dirp; struct dinode *ip; long addr, value, temp, oldaddr, oldvalue, erraddr; long cur_ino = BSIZE * 2; short objsz = 2; short fd, c_count, i, j, k, oldobjsz, error, type; short count, pid, rpid, mode, char_flag, prt_flag; int retcode; unsigned isize; long fsize; char *p, *getblk(); short override = 1; jmp_buf env; /* * main - continuously looping input scanner. Lines are scanned * a character at a time and are processed as soon as * sufficient information has been collected. When an error * is detected, the remainder of the line is flushed. */ main(argc,argv) short argc; char **argv; { register char *cptr; register char c; register short *iptr; #ifdef STANDALONE char devnam[9]; int maj,min; long blk; #endif struct sblock { char block0[512]; struct filsys fs; } sblock; extern long get(); extern long bmap(); extern long getnumb(); extern err(); register struct buf *bp; unsigned block; short offset; /* printf("version 1.4 - 12/15/80 %lu%\n\n");*/ #ifndef STANDALONE setbuf(stdin,NULL); #endif if(argc!=2 && argc!=3) { printf("usage: fsdb /dev/rp??\n"); exit(1); } #if FsTYPE==2 #ifdef vax printf("\nVAX %s assembly\n",ASSEM); #else #ifdef pdp11 printf("\n11/70 %s assembly\n",ASSEM); #else #ifdef u370 printf("\nIBM370 %s assembly\n",ASSEM); #else #ifdef u3b printf("\n3B20S %s assembly\n",ASSEM); #endif #endif #endif #endif #endif if((fd = open(argv[1],2)) < 0) { #ifdef STANDALONE cptr = argv[1]; for(maj = 0; maj <9; devnam[maj++] = *cptr++); if(devnam[8] == '\0'){ maj = 0; min = devnam[7] - '0'; } else { maj = devnam[7]; min = devnam[8]; } if(maj <0 | maj > 3 | min < 0 | min > 5){ printf("invalid device name - %s\n",devnam); exit(1); } if(min == 0) blk = 0l; else blk = 1392l + ((long)(min-1) * 65626l); printf("trying to make node %s %d %d %ld\n",devnam,maj,min,blk); if(MKNOD(devnam,maj,min,blk) < 0){ printf("cannot create %s \n",devnam); exit(1); } if((fd = open(devnam,2)) < 0){ printf("cannot open %s\n",argv[1]); exit(1); } } #else /*printf("cannot open %s\n",argv[1]);*/ perror(argv[0]); exit(1); } #if FsTYPE==2 /* check to see if this is a 1kb or 512b file system */ if (read(fd, &sblock, sizeof sblock) != sizeof sblock) { printf("%s: cannot read superblock\n", argv[0]); exit(1); } #define S sblock.fs if (S.s_magic != FsMAGIC) S.s_type = Fs1b; /* old style fs--default to 512 block */ switch (S.s_type) { case Fs1b: printf("%s(%s): 512 byte Block File System\n", argv[1], S.s_fname); close(fd); if (execvp("/etc/fsdb1b", argv) < 0) { /*printf("%s: cannot exec fsdb1\n", argv[0]);*/ perror(argv[0]); exit(1); } break; case Fs2b: printf("%s(%s): 1K byte Block File System\n", argv[1], S.s_fname); break; default: printf("%s: Invalid File System Type\n", S.s_fname); exit(1); } #endif #endif bhdr.fwd = bhdr.back = &bhdr; for(i=0; i<NBUF; i++) { bp = &buf[i]; bp->blkaddr = buffers[i]; bp->valid = 0; insert(bp); } reload(); if(argc == 3) printf("error checking off\n"); else override = 0; #ifndef STANDALONE signal(2,err); setjmp(env); #endif for(;;) { if(error) { if(c != '\n') while (getc(stdin) != '\n'); c_count = 0; prt_flag = 0; char_flag = 0; error = 0; addr = erraddr; printf("?\n"); /* type = -1; allows "d31 + +" to work */ } c_count++; switch(c = getc(stdin)) { case '\n': /* command end */ erraddr = addr; if(c_count == 1) addr = addr + objsz; c_count = 0; if(prt_flag) { prt_flag = 0; continue; } temp = get(objsz); /* if an error has been flagged, it is probably * due to allignment. This will have set objsz * to 1 hence the next get should work. */ if(error) temp = get(objsz); switch(objsz) { case 1: cptr = ".B"; break; case 2: cptr = ""; break; case 3: cptr = ".A"; break; case 4: cptr = ".D"; break; case DIRSIZ: case 16: if(bcomp(addr,erraddr)) continue; fprnt('d', 1); prt_flag = 0; continue; case 64: fprnt('i',1); cur_ino = addr; prt_flag = 0; continue; } printf("%6.6lo%s: %6.6lo (%ld)\n",addr,cptr,temp,temp); continue; default: /* catch absolute addresses, b and i#'s */ if(c<='9' && c>='0') { ungetc(c,stdin); addr = getnumb(); objsz = 2; value = addr; type = NUMB; continue; } if(feof(stdin)) exit(0); error++; continue; case 'i': /* i# to inode conversion */ if(c_count == 1) { addr = cur_ino; value = get(64); type = INODE; continue; } if(type==NUMB)value = addr; addr = ((value - 1) * sizeof(struct dinode)) + (BSIZE * 2); if(icheck(addr)) continue; cur_ino = addr; value = get(64); type = INODE; continue; case 'b': /* block conversion */ if(type == NUMB)value = addr; addr = value << BSHIFT; value = get(2); type = BLOCK; continue; case 'd': /* directory offsets */ value = getnumb(); if(error||(value > (BSIZE / sizeof(struct direct)) - 1)) { error++; continue; } if(value != 0) if(dircheck()) continue; addr = (addr & ~ADRMSK) + (value * sizeof(struct direct)); value = get(16); /* i-number */ type = DIR; continue; case '\t': case ' ': case '.': continue; case '+': /* address addition */ c = getc(stdin); ungetc(c,stdin); if(c > '9' || c < '0') temp = objsz; else temp = getnumb() * objsz; if(error) continue; if(objsz == DIRSIZ || objsz == 16) if(bcomp(addr,addr+temp)) { c = '+'; continue; } addr = addr + temp; value = get(objsz); continue; case '-': /* address subtraction */ c = getc(stdin); ungetc(c,stdin); if(c > '9' || c < '0') temp = objsz; else temp = getnumb() * objsz; if(error) continue; if(objsz == DIRSIZ || objsz == 16) if(bcomp(addr,addr-temp)) { c = '-'; continue; } addr = addr - temp; value = get(objsz); continue; case '*': temp = getnumb(); if(error) continue; addr = addr * temp; value = get(objsz); continue; case '/': temp = getnumb(); if(error) continue; addr = addr / temp; value = get(objsz); continue; case 'q': /* quit */ if(c_count != 1 || (c = getc(stdin)) != '\n') { error++; continue; } exit(0); case '>': /* save current address */ oldaddr = addr; oldvalue = value; oldobjsz = objsz; continue; case '<': /* restore saved address */ addr = oldaddr; value = oldvalue; objsz = oldobjsz; continue; case 'a': /* access time */ if((c = getc(stdin)) == 't') { addr = cur_ino + AT; type = AT; value = get(4); continue; } /* data block addresses */ ungetc(c,stdin); value = getnumb(); if(error||(value > 12)) { error++; continue; } addr = cur_ino + A0 + (value * 3); value = get(3); type = A0; continue; case 'm': /* mt, md, maj, min */ addr = cur_ino; mode = get(2); if(error) continue; switch(c = getc(stdin)) { case 't': /* modification time */ addr = addr + MT; type = MT; value = get(4); continue; case 'd': /* mode */ addr = addr + MODE; type = MODE; value = get(2); continue; case 'a': /* major device number */ if((c = getc(stdin)) != 'j') { error++; continue; } if(devcheck(mode)) continue; addr = addr + MAJ; value = get(1); type = MAJ; continue; case 'i': /* minor device number */ if((c = getc(stdin)) != 'n') { error++; continue; } if(devcheck(mode)) continue; addr = addr + MIN; value = get(1); type = MIN; continue; } error++; continue; case 's': /* file size */ if((c = getc(stdin)) != 'z') { error++; continue; } addr = cur_ino + SZ; value = get(4); type = SZ; continue; case 'l': /* link count */ if((c = getc(stdin)) != 'n') { error++; continue; } addr = cur_ino + LINK; value = get(2); type = LINK; continue; case 'g': /* group id */ if((c=getc(stdin))!= 'i' || (c=getc(stdin)) != 'd') { error++; continue; } addr = cur_ino + GID; value = get(2); type = GID; continue; case 'u': /* user id */ if((c=getc(stdin))!= 'i' || (c=getc(stdin)) != 'd') { error++; continue; } addr = cur_ino + UID; value = get(1); type = UID; continue; case 'n': /* directory name */ if((c = getc(stdin)) != 'm') { error++; continue; } if(dircheck()) continue; type = DIR; objsz = DIRSIZ; addr = (addr & ~017) + 2; continue; case '=': /* assignment operation */ switch(c = getc(stdin)) { case '"': /* character string */ puta(); continue; case '+': /* =+ operator */ temp = getnumb(); value = get(objsz); if(!error) put(value+temp,objsz); continue; case '-': /* =- operator */ temp = getnumb(); value = get(objsz); if(!error) put(value-temp,objsz); continue; default: /* nm and regular assignment */ ungetc(c,stdin); if((type == DIR) && (c > '9' || c < '0')) { addr = (addr & ~017) + 2; puta(); continue; } value = getnumb(); if(!error) put(value,objsz); continue; } case '!': /* shell command */ #ifdef STANDALONE printf("Shell not available stand-alone"); continue; #else if(c_count != 1) { error++; continue; } if((pid = fork()) == 0) { execl("/bin/sh", "sh", "-t", 0); error++; continue; } while((rpid = wait(&retcode)) != pid && rpid != -1); printf("!\n"); c_count = 0; continue; #endif case 'F': /* buffer status */ for(bp=bhdr.fwd; bp!= &bhdr; bp=bp->fwd) printf("%6lu %d\n",bp->blkno,bp->valid); continue; case 'f': /* file print facility */ if((c=getc(stdin)) >= '0' && c <= '9') { ungetc(c,stdin); temp = getnumb(); if (error) continue; c = getc(stdin); } else temp = 0; count = 0; addr = cur_ino; mode = get(2); if(!override) { if((mode & IFMT)==0) printf("warning: inode not allocated\n"); } if(mode & IFCHR) { printf("special device\n"); error++; continue; } if((addr = (bmap(temp)) << BSHIFT) == 0) continue; fprnt(c,0); continue; case 'O': /* override flip flop */ if(override = !override) printf("error checking off\n"); else { printf("error checking on\n"); reload(); } prt_flag++; continue; case 'B': /* byte offsets */ objsz = 1; continue; case 'W': /* word offsets */ objsz = 2; addr = addr & ~01; continue; case 'D': /* double word offsets */ objsz = 4; addr = addr & ~01; continue; #ifndef STANDALONE case 'A': abort(); #endif case ',': /* general print facilities */ case 'p': if(( c = getc(stdin)) >= '0' && c <= '9') { ungetc(c,stdin); count = getnumb(); if(error) continue; if((count < 0) || (count > BSIZE)) count = 1; c = getc(stdin); } else if(c == '*'){ count = 0; /* print to end of block */ c = getc(stdin); } else count = 1; fprnt(c,count); } } } /* * getnumb - read a number from the input stream. A leading * zero signifies octal interpretation. If the first character * is not numeric this is an error, otherwise continue * until the first non-numeric. */ long getnumb() { extern short error; long number, base; register char c; if(((c = getc(stdin)) < '0')||(c > '9')) { error++; ungetc(c,stdin); return(-1); } if(c == '0') base = 8; else base = 10; number = c - '0'; while(((c = getc(stdin)) >= '0' )&&( c <= '9')) { if((base == 8) && ((c =='8')||(c == '9'))) { error++; return(-1); } number = number * base + c - '0'; } ungetc(c,stdin); return(number); } /* * get - read a byte, word or double word from the file system. * The entire block containing the desired item is read * and the appropriate data is extracted and returned. * Inode and directory size requests result in word * fetches. Directory names (objsz == DIRSIZ) result in byte * fetches. */ long get(lngth) short lngth; { long vtemp; char *bptr; short offset; objsz = lngth; if(allign(objsz)) return(-1); if((bptr = getblk(addr)) == 0) return(-1); vtemp = 0; offset = addr & ADRMSK; bptr = bptr + offset; if(offset + lngth > BSIZE) { error++; printf ("get(lngth) - %d too long\n",offset + lngth); return(-1); } switch(objsz) { case 4: vtemp = *(long *)bptr; return(vtemp); case 64: case 16: case 2: loword(vtemp) = *(short *)bptr; return(vtemp); case DIRSIZ: case 1: lobyte(loword(vtemp)) = *bptr; return(vtemp); case 3: l3tol(&vtemp,bptr,1); return(vtemp); } error++; printf ("get(%d) - invalid length\n",lngth); return(0); } /* * icheck - check if the current address is within the I-list. * The I-list extends for isize blocks beginning at the * super block + 1, i.e., from block 2 to block isize. */ icheck(address) long address; { unsigned blk; if(override) return(0); blk = address >> BSHIFT; if((blk >= 2) && (blk < isize)) return(0); printf("inode out of range\n"); error++; return(1); } /* * putf - print a byte as an ascii character if possible. * The exceptions are tabs, newlines, backslashes * and nulls which are printed as the standard c * language escapes. Characters which are not * recognized are printed as \?. */ putf(c) register char c; { if(c<=037 || c>=0177 || c=='\\') { putc('\\',stdout); switch(c) { case '\\': putc('\\',stdout); break; case '\t': putc('t',stdout); break; case '\n': putc('n',stdout); break; case '\0': putc('0',stdout); break; default: putc('?',stdout); } } else { putc(' ',stdout); putc(c,stdout); } putc(' ',stdout); } /* * put - write an item into the buffer for the current address * block. The value is checked to make sure that it will * fit in the size given without truncation. If successful, * the entire block is written back to the file system. */ put(item,lngth) long item; short lngth; { register char *bptr, *sbptr; register long *vptr; short offset; long s_err,nbytes; objsz = lngth; if(allign(objsz)) return(-1); if((sbptr = getblk(addr)) == 0) return; offset = addr & ADRMSK; if(offset + lngth > BSIZE) { error++; printf("block overflow\n"); return; } bptr = sbptr + offset; switch(objsz) { case 3: vptr = &item; if ( ((long)vptr & 1) != 0 ) break; ltol3(bptr,vptr,1); goto rite; case 4: *(long *)bptr = item; goto rite; case 64: case 16: case 2: if(item & ~0177777L) break; *(short *)bptr = item; goto rite; case DIRSIZ: case 1: if(item & ~0377) break; *bptr = lobyte(loword(item)); rite: if((s_err = lseek(fd,addr & ~(long)ADRMSK,0)) == -1) { error++; printf("seek error : %lo\n",addr); return(0); } if((nbytes = write(fd,sbptr,BSIZE)) != BSIZE) { error++; printf("write error : addr = %lo\n",addr); printf(" : s_err = %lo\n",s_err); printf(" : nbytes = %lo\n",nbytes); return(0); } return; default: error++; return; } printf("truncation error\n"); error++; } /* * getblk - check if the desired block is in the file system. * Search the incore buffers to see if the block is already * available. If successful, unlink the buffer control block * from its position in the buffer list and re-insert it at * the head of the list. If failure, use the last buffer * in the list for the desired block. Again, this control * block is placed at the head of the list. This process * will leave commonly requested blocks in the in-core buffers. * Finally, a pointer to the buffer is returned. */ char *getblk(address) long address; { register struct buf *bp; long block; long s_err,nbytes; block = addr >> BSHIFT; if(!override) if(block >= fsize) { printf("block out of range\n"); error++; return(0); } for(bp=bhdr.fwd; bp!= &bhdr; bp=bp->fwd) if(bp->blkno==block && bp->valid) goto xit; bp = bhdr.back; bp->blkno = block; bp->valid = 0; if((s_err = lseek(fd,addr & ~(long)ADRMSK,0)) == -1) { error++; printf("seek error : %lo\n",addr); return(0); } if((nbytes = read(fd,bp->blkaddr,BSIZE)) != BSIZE) { error++; printf("read error : addr = %lo\n",addr); printf(" : s_err = %lo\n",s_err); printf(" : nbytes = %lo\n",nbytes); return(0); } bp->valid++; xit: bp->back->fwd = bp->fwd; bp->fwd->back = bp->back; insert(bp); return(bp->blkaddr); } /* * insert - place the designated buffer control block * at the head of the linked list of buffers. */ insert(bp) register struct buf *bp; { bp->back = &bhdr; bp->fwd = bhdr.fwd; bhdr.fwd->back = bp; bhdr.fwd = bp; } /* * allign - before a get or put operation check the * current address for a boundary corresponding to the * size of the object. */ allign(ment) short ment; { switch(ment) { case 4: if(addr & 01L) break; return(0); case DIRSIZ: if((addr & 017) != 02) break; return(0); case 16: case 64: case 2: if(addr & 01L) break; case 3: case 1: return(0); } error++; objsz = 1; printf("allignment\n"); return(1); } /* * err - called on interrupts. Set the current address * back to the last address stored in erraddr. Reset all * appropriate flags. If the prt_flag is set, the interrupt * occured while transferring characters to a buffer. * These are "erased" by invalidating the buffer, causing * the entire block to be re-read upon the next reference. * A reset call is made to return to the main loop; */ err() { #ifndef STANDALONE signal(2,err); addr = erraddr; error = 0; c_count = 0; if(char_flag) { bhdr.fwd->valid = 0; char_flag = 0; } prt_flag = 0; printf("\n?\n"); fseek(stdin, 0L, 2); longjmp(env,0); #endif } /* * devcheck - check that the given mode represents a * special device. The IFCHR bit is on for both * character and block devices. */ devcheck(md) register short md; { if(override) return(0); if(md & IFCHR) return(0); printf("not char or block device\n"); error++; return(1); } /* * nullblk - return error if address is zero. This is done * to prevent block 0 from being used as an indirect block * for a large file or as a data block for a small file. */ nullblk(bn) long bn; { if(bn != 0) return(0); printf("non existent block\n"); error++; return(1); } /* * dircheck - check if the current address can be in a directory. * This means it is not in the I-list, block 0 or the super block. */ dircheck() { unsigned block; if(override) return (0); if((block = (addr >> BSHIFT)) >= isize) return(0); error++; printf("block in I-list\n"); return(1); } /* * puta - put ascii characters into a buffer. The string * terminates with a quote or newline. The leading quote, * which is optional for directory names, was stripped off * by the assignment case in the main loop. If the type * indicates a directory name, the entry is null padded to * DIRSIZ bytes. If more than 14 characters have been given * with this type or, in any case, if a block overflow * occurs, the current block is made invalid. See the * description for err. */ puta() { register char *bptr, c; register offset; char *sbptr; unsigned block; long s_err,nbytes; if((sbptr = getblk(addr)) == 0) return; char_flag++; offset = addr & ADRMSK; bptr = sbptr + offset; while((c = getc(stdin)) != '"') { if(offset++ == BSIZE) { bhdr.fwd->valid = 0; error++; char_flag = 0; printf("block overflow\n"); return; } if(c == '\n') { ungetc(c,stdin); break; } if(c == '\\') { switch(c = getc(stdin)) { case 't': *bptr++ = '\t'; break; case 'n': *bptr++ = '\n'; break; case '0': *bptr++ = '\0'; break; default: *bptr++ = c; break; } } else *bptr++ = c; } char_flag = 0; if(type == DIR) { c = offset - (addr & ADRMSK); if(c > DIRSIZ) { bhdr.fwd->valid = 0; error++; char_flag = 0; printf("name too long\n"); return; } while(c++ < DIRSIZ) *bptr++ = '\0'; } if((s_err = lseek(fd,addr & ~(long)ADRMSK,0)) == -1) { error++; printf("seek error : %lo\n",addr); return(0); } if((nbytes = write(fd,sbptr,BSIZE)) != BSIZE) { error++; printf("write error : addr = %lo\n",addr); printf(" : s_err = %lo\n",s_err); printf(" : nbytes = %lo\n",nbytes); return(0); } } /* * fprnt - print data as characters, octal or decimal words, octal * bytes, directories or inodes A total of "count" entries * are printed. A zero count will print all entries to the * end of the current block. If the printing would cross a * block boundary, the attempt is aborted and an error returned. * This is done since logically sequential blocks are generally * not physically sequential. The error address is set * after each entry is printed. Upon completion, the current * address is set to that of the last entry printed. */ fprnt(style,count) register char style; register count; { short offset; unsigned block; char *cptr; short *iptr; short *tptr; long tmp; prt_flag++; block = addr >> BSHIFT; offset = addr & ADRMSK; if((cptr = getblk(addr)) == 0){ ip = 0; iptr = 0; dirp = 0; return; } ip = ((struct dinode *)cptr); erraddr = addr; switch (style) { case 'c': /* print as characters */ case 'b': /* or octal bytes */ if(count == 0) count = BSIZE - offset; if(offset + count > BSIZE) break; objsz = 1; cptr = cptr + offset; for(i=0; count--; i++) { if(i % 16 == 0) printf("\n%6.6lo: ",addr); if(style == 'c') putf(*cptr++); else printf("%4.4o",*cptr++ & 0377); erraddr = addr; addr++; } addr--; putc('\n',stdout); return; case 'd': /* print as directories */ if(dircheck()) return; addr = addr & ~017; offset = offset / sizeof(struct direct); if(count == 0) count = (BSIZE / sizeof(struct direct)) - offset; if(count + offset > (BSIZE / sizeof(struct direct))) break; type = DIR; objsz = 16; for(dirp = ((struct dir *)cptr) + offset; count--; dirp++) { printf("d%d: %4d ",offset++,dirp->inumb); cptr = dirp->nm; for(j=0; j<DIRSIZ; j++) { if(*cptr == '\0') break; putf(*cptr++); } putc('\n',stdout); erraddr = addr; addr = addr + sizeof(struct direct); } addr = erraddr; return; case 'o': /* print as octal words */ case 'e': /* print as decimal words */ addr = addr & ~01; offset = offset >> 1; iptr = ((short *)cptr) + offset; if(count == 0) count = BSIZE / 2 - offset; if(offset + count > BSIZE / 2) break; objsz = 2; for(i=0; count--; i++) { if(i % 8 == 0) { /* this code deletes lines of zeros */ tptr = iptr; k = count -1; /* always print last line */ for(j = i; k--; j++) if(*tptr++ != 0) break; if(j > (i + 7)) { j = (j - i) >> 3; while(j-- > 0){ iptr = iptr + 8; count = count - 8; i = i + 8; addr = addr + 16; } printf("\n*"); } printf("\n%6.7lo:",addr); } if(style == 'o')printf(" %6.6o",*iptr++ & 0177777); else printf(" %6d",*iptr++); erraddr = addr; addr = addr + 2; } addr = erraddr; putc('\n',stdout); return; case 'i': /* print as inodes */ if(icheck(addr)) return; addr = addr & ~077; offset = offset / sizeof(struct dinode); if(count == 0) count = INOSZ - offset; if(count + offset > INOSZ) break; type = INODE; objsz = 64; ip = ip + offset; temp = (addr - (BSIZE * 2)) / sizeof(struct dinode) + 1; for(i=0; count--; ip++) { printf("i#:%6ld md: ",temp++); p = " ugtrwxrwxrwx"; mode = ip->di_mode; switch(mode & IFMT) { case IFDIR: putc('d',stdout); break; case IFCHR: putc('c',stdout); break; case IFBLK: putc('b',stdout); break; case IFREG: putc('f',stdout); break; case IFIFO: putc('p',stdout); break; default: putc('-',stdout); break; } for(mode = mode << 4; *++p; mode = mode << 1) { if(mode & HIBIT) putc(*p,stdout); else putc('-',stdout); } printf(" ln:%5d uid:%5d gid:%5d", ip->di_nlink,ip->di_uid,ip->di_gid); printf(" sz: %8lu\n", ip->di_size); if(ip->di_mode & IFCHR) printf("maj:%3.3o min:%3.3o ", ip->di_addr[1] & 0377, ip->di_addr[0] & 0377); else { for(i = 0; i < NADDR; i++) { l3tol(&tmp,&ip->di_addr[3*i],1); printf("a%d:%6lu ",i,tmp); if(i == 6) putc('\n',stdout); } putc('\n',stdout); } printf("at: %s",ctime(&ip->di_atime)); printf("mt: %s",ctime(&ip->di_mtime)); printf("ct: %s",ctime(&ip->di_ctime)); if(count) putc('\n',stdout); cur_ino = erraddr = addr; addr = addr + sizeof(struct dinode); } addr = erraddr; return; default: error++; printf("no such print option\n"); return; } error++; printf("block overflow\n"); } /* * reload - read new values for isize and fsize. These are * the basis for most of the error checking procedures. */ reload() { long saddr; short sv_objsz; saddr = addr; sv_objsz = objsz; #if FsTYPE==2 addr = BSIZE / 2; #else addr = BSIZE; #endif isize = get(2); #if FsTYPE==2 addr = BSIZE / 2 + 4; #else addr = SLOC; #endif fsize = get(4); addr = saddr; objsz = sv_objsz; if(error) printf("cannot read superblock\n"); else printf("FSIZE = %ld, ISIZE = %u\n", fsize, (isize - 2) * INOSZ); } /* * bcomp - compare the block numbers of two long addresses. * Used to check for block over/under flows when stepping through * a file system. */ bcomp(addr1,addr2) long addr1; long addr2; { if(override) return(0); if((addr1 & ~(long)ADRMSK) == (addr2 & ~(long)ADRMSK)) return(0); error++; printf("block overflow\n"); return(1); } /* * bmap - maps the logical block number of a file into * the corresponding physical block on the file * system. Algorithm is that of the version 7 bmap routine. */ long bmap(bn) long bn; { long nb; int j, sh, i; addr = cur_ino; if(bn < NADDR - 3) { addr += A0 + bn * 3; return(nullblk(nb=get(3)) ? 0L : nb); } sh = 0; nb = 1; bn -= NADDR - 3; for(j=3; j>0; j--) { sh += NSHIFT; nb = nb << NSHIFT; if(bn < nb) break; bn -= nb; } if(j==0) { error++; printf("file too big\n"); return(0L); } addr += A0 + (NADDR - j) * 3; if(nullblk(nb=get(3))) return(0L); for(; j<=3; j++) { sh -= NSHIFT; addr = (nb << BSHIFT) + 4 * ((bn >> sh) & NMASK); if(nullblk(nb=get(4))) return(0L); } return(nb); }