/* $Header: /usr/staff/envy/architec/src/efslook/RCS/efslook.c,v 1.2 92/01/24 15:24:35 architec Exp Locker: architec $ */ /* * $Log: efslook.c,v $ * Revision 1.2 92/01/24 15:24:35 architec * cleaned up * added -f (find efs) * * Revision 1.1 92/01/23 17:37:30 architec * Initial revision * */ #include #include #include #include #include #include #include /*#include */ #include #include static char * prog_name; static off64_t offset, find_offsets; static int remote_fd_in, remote_fd_out; static int local_read, local_fd; static void efs_read( void * buf, off64_t from, long len); static void usage() { (void) fprintf( stderr, "usage: %s [-h] [-f] [-o] \n", prog_name); } static void help() { (void) fprintf( stderr, "\n"); usage(); (void) fprintf( stderr, "\n"); (void) fprintf( stderr, " where ...\n"); (void) fprintf( stderr, "\n"); (void) fprintf( stderr, " -h : this help message\n"); (void) fprintf( stderr, " -f : find file system offsets\n"); (void) fprintf( stderr, " -o : offset (in 512 byte blocks)\n"); (void) fprintf( stderr, " : file to examine\n"); (void) fprintf( stderr, "\n"); } static char * parse_command_line( argc, argv) int argc; char ** argv; { int arg; char * filename; filename = (char *) 0; offset = 0; find_offsets = 0; prog_name = (prog_name = strrchr( argv[ 0], '/')) ? (prog_name + 1) : argv[ 0]; for( arg = 1; arg < argc; arg++) { if( argv[ arg][ 0] == '-') { switch( argv[ arg][ 1]) { case 'h': help(); exit( 1); break; case 'o': offset = (off64_t) atoll( argv[ arg] + 2); break; case 'f': find_offsets = 1; break; default: usage(); exit( 1); break; } } else { filename = argv[ arg]; } } if( !filename) { usage(); exit( 1); } return( filename); } static void efs_read( buf, from, len) void * buf; off64_t from; long len; { char *buffer; long rlen; off64_t rfrom; off64_t remain; from += (offset * 512); fprintf(stderr,"lseek %llu, read %ld\n",from, len); if( local_read) { rlen = len + 512 &~ 511; buffer = (char *)malloc(rlen); rfrom = from; if ( rfrom % 512 != 0 ) { remain = rfrom % 512; rfrom -= remain; } else { remain = 0L; } if ( rfrom != lseek64( local_fd, rfrom, SEEK_SET)) perror("lseek"); if ( rlen != read( local_fd, buffer, rlen)) perror("read"); memcpy( buf, buffer + remain, len); free(buffer); } else { char command[ 80]; int amount_read; sprintf( command, "%d %d\n", from, len); write( remote_fd_out, command, strlen( command)); amount_read = 0; do { int read_status; if( (read_status = read( remote_fd_in, (void *) (((char *) buf) + amount_read), len - amount_read)) <= 0) { perror( "read"); exit( 1); } amount_read += read_status; } while (amount_read < len); } } static struct efs efs_header() { struct efs efs; char fs_fname[ 7]; char fs_fpack[ 7]; efs_read( (void *) (&efs), 512, sizeof( struct efs)); puts( "\nefs super block info\n"); printf( "size of filesystem, in sectors : %6ld\n", efs.fs_size); printf( "num cylinder groups : %6ld\n", efs.fs_ncg); printf( "bb offset to first cg : %6ld\n", efs.fs_firstcg); printf( "size of cylinder group in bb's : %6ld\n", efs.fs_cgfsize); printf( "bb's in inodes per cylinder group : %6ld\n", efs.fs_cgisize); printf( "total free data blocks : %6ld\n", efs.fs_tfree); printf( "total free inodes : %6ld\n", efs.fs_tinode); strncpy( fs_fname, efs.fs_fname, 6); fs_fname[ 6] = '\0'; printf( "file system name : %6s\n", fs_fname); strncpy( fs_fpack, efs.fs_fpack, 6); fs_fpack[ 6] = '\0'; printf( "file system pack name : %6s\n", fs_fpack); puts( ""); if( (efs.fs_magic != EFS_MAGIC) || (efs.fs_size <= 0) || (efs.fs_ncg <= 0) || (efs.fs_firstcg <= 0) || (efs.fs_cgfsize <= 0) || (efs.fs_cgisize <= 0) || (efs.fs_tfree <= 0) || (efs.fs_tinode <= 0)) { fprintf( stderr, "%s: bad efs super block (prob wrong offset)\n", prog_name); exit( 1); } return( efs); } static void efs_exinode( efs, inode_num, savefile) struct efs efs; int inode_num; char * savefile; { struct efs_dinode inode; long cg; long in; int outfd; cg = inode_num / (efs.fs_cgisize * (512 / sizeof( struct efs_dinode))); in = inode_num % (efs.fs_cgisize * (512 / sizeof( struct efs_dinode))); printf( "inode %2d [%d:%d]\n", inode_num, cg, in); efs_read( (void *) (&inode), (off64_t) (512 * (efs.fs_firstcg + efs.fs_cgfsize * cg)) + (sizeof( struct efs_dinode) * in), sizeof( struct efs_dinode)); printf( "access permissions : 0%04o\n", inode.di_mode & 07777); printf( "owner's user id number : %10d\n", inode.di_uid); printf( "group's group id number : %10d\n", inode.di_gid); printf( "number of bytes in file : %10d\n", inode.di_size); printf( "number of extents : %10d\n", inode.di_numextents); if( inode.di_mode & S_IFDIR) { puts( "directory"); } else if( inode.di_mode & S_IFREG) { puts( "regular"); } else { puts( "other"); return; } if( savefile && !(inode.di_mode & S_IFREG)) { puts( "not regular file\nget aborted"); return; } if( savefile) { if( (outfd = open( savefile, O_RDWR | O_CREAT, 0600)) < 0) { perror( savefile); exit( 1); } } if( inode.di_numextents <= EFS_DIRECTEXTENTS) { int extent_num; for( extent_num = 0; extent_num < inode.di_numextents; extent_num ++) { if( savefile) { char buf[ 512 * 256]; lseek( outfd, 512 * inode.di_u.di_extents[ extent_num].ex_offset, SEEK_SET); printf( "reading %3d / %3d\n", extent_num + 1, inode.di_numextents); efs_read( buf, (512 * inode.di_u.di_extents[ extent_num].ex_bn), (512 * inode.di_u.di_extents[ extent_num].ex_length)); write( outfd, buf, 512 * inode.di_u.di_extents[ extent_num].ex_length); } else { printf( "\textent %d\n", extent_num); printf( "\tbb # on volume : %10d\n", inode.di_u.di_extents[ extent_num].ex_bn); printf( "\tlength of this extent in bb's : %10d\n", inode.di_u.di_extents[ extent_num].ex_length); printf( "\tlogical file offset in bb's : %10d\n", inode.di_u.di_extents[ extent_num].ex_offset); if( inode.di_mode & S_IFDIR) { struct efs_dirblk dir; int block; puts( "\t\tdir"); for( block = 0; block < inode.di_u.di_extents[ extent_num].ex_length; block ++) { efs_read( (void *) (&dir), (512 * inode.di_u.di_extents[ extent_num].ex_bn) + (block * sizeof( struct efs_dirblk)), sizeof( struct efs_dirblk)); printf( "\t\tfirstused : %10d\n", dir.firstused); printf( "\t\tslots : %10d\n", dir.slots); { int slot; puts( "\t\t\toff : inode name"); for( slot = 0; slot < dir.slots; slot ++) { char name[ 256]; struct efs_dent * ent; if( dir.space[ slot] != 0) { ent = (struct efs_dent *) (((char *) (&dir)) + (dir.space[ slot] << 1)); strncpy( name, ent->d_name, ent->d_namelen); name[ ent->d_namelen] = '\0'; printf( "\t\t\t%3d : %5d %s\n", dir.space[ slot] << 1, ent->ud_inum.s[ 1], name); } else { printf( "\t\t\t***\n"); } } } puts( ""); } } } puts( ""); } } else { int extent_num; for( extent_num = 0; extent_num < inode.di_u.di_extents[ extent_num].ex_offset; extent_num ++) { int block; int num_extents_done; printf( "\textent %d\n", extent_num); printf( "\tbb # on volume : %10d\n", inode.di_u.di_extents[ extent_num].ex_bn); printf( "\tlength of this extent in bb's : %10d\n", inode.di_u.di_extents[ extent_num].ex_length); printf( "\tlogical file offset in bb's : %10d\n", inode.di_u.di_extents[ extent_num].ex_offset); num_extents_done = 0; for( block = 0; block < inode.di_u.di_extents[ extent_num].ex_length; block ++) { extent extents[ 512 / sizeof( extent)]; int indirect_extent_num; printf( "\tblock %d\n", block); efs_read( (void *) extents, (512 * (inode.di_u.di_extents[ extent_num].ex_bn + block)), 512); for( indirect_extent_num = 0; (indirect_extent_num < (512 / sizeof( extent))) && (num_extents_done < inode.di_numextents); indirect_extent_num ++, num_extents_done ++) { if( savefile) { char buf[ 256 * 512]; lseek64( outfd, 512 * extents[ indirect_extent_num].ex_offset, SEEK_SET); printf( "reading %3d / %3d\n", num_extents_done + 1, inode.di_numextents); efs_read( buf, (512 * extents[ indirect_extent_num].ex_bn), (512 * extents[ indirect_extent_num].ex_length)); write( outfd, buf, 512 * extents[ indirect_extent_num].ex_length); } else { printf( "\t\textent %d\n", indirect_extent_num); printf( "\t\tbb # on volume : %10d\n", extents[ indirect_extent_num].ex_bn); printf( "\t\tlength of this extent in bb's : %10d\n", extents[ indirect_extent_num].ex_length); printf( "\t\tlogical file offset in bb's : %10d\n", extents[ indirect_extent_num].ex_offset); puts( ""); } } } } } if( savefile) { ftruncate( outfd, inode.di_size); close( outfd); } puts( ""); } #define BF 64 static void efs_find_offsets() { int block, blocks_read; char buf[ 512 * BF]; blocks_read = 0; /* will exit when read error (maybe) */ while( 1) { printf( "%8d\r", blocks_read); fflush( stdout); efs_read( (void *) buf, blocks_read * 512, 512 * BF); for( block = 0; block < BF; block ++) { struct efs * efs; efs = (struct efs *) (buf + 512 * block); if( efs->fs_magic == EFS_MAGIC) { printf( "efs found at block offset %ld\n", blocks_read + block - 1); } } blocks_read += BF; } } static void efs_open_remote( remote_host, remote_device) char * remote_host, * remote_device; { int pipe_out[ 2], pipe_in[ 2]; pipe( pipe_out); pipe( pipe_in); switch( fork()) { case -1: perror( "fork"); exit( 1); break; case 0: close( pipe_out[ 1]); close( pipe_in[ 0]); close( 0); dup( pipe_out[ 0]); close( pipe_out[ 0]); close( 1); dup( pipe_in[ 1]); close( pipe_in[ 1]); execl( "/usr/bsd/rsh", "rsh", remote_host, "efslook_remote", remote_device, (char *) 0); perror( "execl"); exit( 1); break; default: close( pipe_out[ 0]); close( pipe_in[ 1]); remote_fd_out = pipe_out[ 1]; remote_fd_in = pipe_in[ 0]; break; } } static void efs_command_help() { puts( "\nefslook commands\n"); puts( "ex : examine inode"); puts( "get : extract inode into file"); puts( "quit : quit from efslook"); puts( ""); } int main( argc, argv) int argc; char ** argv; { char * filename; struct efs efs; char * remote_device, * remote_host; filename = parse_command_line( argc, argv); if( remote_device = strchr( filename, ':')) { char command[ 80]; *remote_device = '\0'; remote_device ++; remote_host = filename; efs_open_remote( remote_host, remote_device); local_read = 0; } else { if( (local_fd = open( filename, O_RDONLY)) < 0) { perror( filename); exit( 1); } local_read = 1; } if( find_offsets) { efs_find_offsets(); } else { efs = efs_header(); efs_exinode( efs, 2); { char command[ 80]; int quit; quit = 0; do { printf( "efs > "); fflush( stdout); fgets( command, 80, stdin); switch( command[ 0]) { case 'e': { int inode; if( sscanf( command, "%*s %d", &inode) == 1) { efs_exinode( efs, inode, (char *) 0); } else { puts( "syntax error"); } } break; case 'g': { int inode; char savefile[ 80]; if( sscanf( command, "%*s %d %s", &inode, savefile) == 2) { efs_exinode( efs, inode, savefile); } else { puts( "syntax error"); } } break; case 'q': quit = 1; break; case '?': case 'h': efs_command_help(); break; default: puts( "bad command"); efs_command_help(); break; } } while( !quit); } if( local_fd) { close( local_fd); } else { close( remote_fd_in); close( remote_fd_out); } } return( 0); }