/***************************************************************************** * rsb.c - Read Super Block. Allows a jfs superblock to be dumped, inode * table to be listed or specific inodes data pointers to be chased and * dumped to standard out (undelete). * * Phil Gibbs - Trinem Consulting (pgibbs@trinem.co.uk) ****************************************************************************/ #include #include #include #include #include #include #include #include #define FOUR_MB (1024*1024*4) #define THIRTY_TWO_KB (1024*32) extern int optind; extern int Optopt; extern int Opterr; extern char *optarg; void PrintSep() { int k=80; while (k) { putchar('-'); k--; } putchar('\n'); } char *UserName(uid_t uid) { char replystr[10]; struct passwd *res; res=getpwuid(uid); if (res->pw_name[0]) { return res->pw_name; } else { sprintf(replystr,"%d",uid); return replystr; } } char *GroupName(gid_t gid) { struct group *res; res=getgrgid(gid); return res->gr_name; } ulong NumberOfInodes(struct superblock *sb) { ulong MaxInodes; ulong TotalFrags; if (sb->s_version==fsv3pvers) { TotalFrags=(sb->s_fsize*512)/sb->s_fragsize; MaxInodes=(TotalFrags/sb->s_agsize)*sb->s_iagsize; } else { MaxInodes=(sb->s_fsize*512)/sb->s_bsize; } return MaxInodes; } void AnalyseSuperBlock(struct superblock *sb) { ulong TotalFrags; PrintSep(); printf("SuperBlock Details:\n-------------------\n"); printf("File system size: %ld x 512 bytes (%ld Mb)\n", sb->s_fsize, (sb->s_fsize*512)/(1024*1024)); printf("Block size: %d bytes\n",sb->s_bsize); printf("Flags: "); switch (sb->s_fmod) { case (char)FM_CLEAN: break; case (char)FM_MOUNT: printf("mounted "); break; case (char)FM_MDIRTY: printf("mounted dirty "); break; case (char)FM_LOGREDO: printf("log redo failed "); break; default: printf("Unknown flag "); break; } if (sb->s_ronly) printf("(read-only)"); printf("\n"); printf("Last SB update at: %s",ctime(&(sb->s_time))); printf("Version: %s\n", sb->s_version?"1 - fsv3pvers":"0 - fsv3vers"); printf("\n"); if (sb->s_version==fsv3pvers) { TotalFrags=(sb->s_fsize*512)/sb->s_fragsize; printf("Fragment size: %5d ",sb->s_fragsize); printf("inodes per alloc: %8d\n",sb->s_iagsize); printf("Frags per alloc: %5d ",sb->s_agsize); printf("Total Fragments: %8d\n",TotalFrags); printf("Total Alloc Grps: %5d ", TotalFrags/sb->s_agsize); printf("Max inodes: %8ld\n",NumberOfInodes(sb)); } else { printf("Total Alloc Grps: %5d ", (sb->s_fsize*512)/sb->s_agsize); printf("inodes per alloc: %8d\n",sb->s_agsize); printf("Max inodes: %8ld\n",NumberOfInodes(sb)); } PrintSep(); } void ReadInode( FILE *in, ulong StartInum, struct dinode *inode, ulong InodesPerAllocBlock, ulong AllocBlockSize) { off_t SeekPoint; long BlockNumber; int OffsetInBlock; static struct dinode I_NODES[PAGESIZE/DILENGTH]; ulong AllocBlock; ulong inum; static off_t LastSeekPoint=-1; AllocBlock=(StartInum/InodesPerAllocBlock); BlockNumber=(StartInum-(AllocBlock*InodesPerAllocBlock))/ (PAGESIZE/DILENGTH); OffsetInBlock=(StartInum-(AllocBlock*InodesPerAllocBlock))- (BlockNumber*(PAGESIZE/DILENGTH)); SeekPoint=(AllocBlock)? (BlockNumber*PAGESIZE)+(AllocBlock*AllocBlockSize): (BlockNumber*PAGESIZE)+(INODES_B*PAGESIZE); if (SeekPoint!=LastSeekPoint) { sync(); fseek(in,SeekPoint,SEEK_SET); fread(I_NODES,PAGESIZE,1,in); LastSeekPoint=SeekPoint; } *inode=I_NODES[OffsetInBlock]; } void DumpInodeContents( long inode, FILE *in, ulong InodesPerAllocBlock, ulong AllocBlockSize, ulong Mask, ulong Multiplier) { struct dinode DiskInode; ulong SeekPoint; char Buffer[4096]; ulong FileSize; int k; int BytesToRead; ulong *DiskPointers; int NumPtrs; ReadInode( in, inode, &DiskInode, InodesPerAllocBlock, AllocBlockSize); FileSize=DiskInode.di_size; if (FileSize>FOUR_MB) { /* Double indirect mapping */ } else if (FileSize>THIRTY_TWO_KB) { /* Indirect mapping */ SeekPoint=DiskInode.di_rindirect & Mask; SeekPoint=SeekPoint*Multiplier; DiskPointers=(ulong *)malloc(1024*sizeof(ulong)); fseek(in,SeekPoint,SEEK_SET); fread(DiskPointers,1024*sizeof(ulong),1,in); NumPtrs=1024; } else { /* Direct Mapping */ DiskPointers=&(DiskInode.di_rdaddr[0]); NumPtrs=8; } for (k=0;k<=NumPtrs && FileSize;k++) { SeekPoint=(DiskPointers[k] & Mask); SeekPoint=SeekPoint*Multiplier; BytesToRead=(FileSize>sizeof(Buffer))?sizeof(Buffer):FileSize; fseek(in,SeekPoint,SEEK_SET); fread(Buffer,BytesToRead,1,in); FileSize=FileSize-BytesToRead; write(1,Buffer,BytesToRead); } } void DumpInodeList( FILE *in, ulong MaxInodes, ulong InodesPerAllocBlock, ulong AllocBlockSize) { long inode; struct dinode DiskInode; struct tm *TimeStruct; printf(" Inode Links User Group Size ModDate\n"); printf("-------- ----- -------- -------- -------- -------\n"); for (inode=0;inode<=MaxInodes;inode++) { ReadInode( in, inode, &DiskInode, InodesPerAllocBlock, AllocBlockSize); if (DiskInode.di_mtime) { TimeStruct=localtime((long *)&DiskInode.di_mtime); printf("%8d %5d %8s %8s %8d %02d/%02d/%4d\n", inode, DiskInode.di_nlink, UserName(DiskInode.di_uid), GroupName(DiskInode.di_gid), DiskInode.di_size, TimeStruct->tm_mday, TimeStruct->tm_mon, TimeStruct->tm_year+1900); } } } void ExitWithUsageMessage() { fprintf(stderr,"USAGE: rsb [-i inode] [-d] [-s] \n"); exit(1); } main(int argc,char **argv) { FILE *in; struct superblock SuperBlock; short Valid; long inode=0; struct dinode DiskInode; ulong AllocBlockSize; ulong InodesPerAllocBlock; ulong MaxInodes; ulong Mask; ulong Multiplier; int option; int DumpSuperBlockFlag=0; int DumpFlag=0; while ((option=getopt(argc,argv,"i:ds")) != EOF) { switch(option) { case 'i': /* Inode specified */ inode=atol(optarg); break; case 'd': /* Dump flag */ DumpFlag=1; break; case 's': /* List Superblock flag */ DumpSuperBlockFlag=1; break; default: break; } } if (strlen(argv[optind])) in=fopen(argv[optind],"r"); else ExitWithUsageMessage(); if (in) { fseek(in,SUPER_B*PAGESIZE,SEEK_SET); fread(&SuperBlock,sizeof(SuperBlock),1,in); switch (SuperBlock.s_version) { case fsv3pvers: Valid=!strncmp(SuperBlock.s_magic,fsv3pmagic,4); InodesPerAllocBlock=SuperBlock.s_iagsize; AllocBlockSize= SuperBlock.s_fragsize*SuperBlock.s_agsize; Multiplier=SuperBlock.s_fragsize; Mask=0x3ffffff; break; case fsv3vers: Valid=!strncmp(SuperBlock.s_magic,fsv3magic,4); InodesPerAllocBlock=SuperBlock.s_agsize; AllocBlockSize=SuperBlock.s_agsize*PAGESIZE; Multiplier=SuperBlock.s_bsize; Mask=0xfffffff; break; default: Valid=0; break; } if (Valid) { if (DumpSuperBlockFlag==1) { AnalyseSuperBlock(&SuperBlock); } MaxInodes=NumberOfInodes(&SuperBlock); if (DumpFlag==1) { if (inode) DumpInodeContents(inode,in,InodesPerAllocBlock,AllocBlockSize,Mask,Multiplier); else DumpInodeList(in,MaxInodes,InodesPerAllocBlock,AllocBlockSize); } } else { fprintf(stderr,"Superblock - bad magic number\n"); exit(1); } } else { fprintf(stderr,"couldn't open "); perror(argv[optind]); exit(1); } }