Hare fsdb Listing 5


#! perl
eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
& eval 'exec perl -S $0 $argv:q'
if 0;
#
# Copyright 1992, Chris Hare
#
#
# This PERL script is designed to read the superblock of the given 
# filesystem name, and to print a report on it.  While this version is
# coupled to the standard AT&T S51K filesystem, it may work with some other
# filesystem formats, so long as the superblock is the same.
#
# Load the configuration file with the filesystem superblock information
#
require "config.fs";
#
# set the filesystem block size type information
#
$Types{'1'} = 512;			# 512 byte blocks
$Types{'2'} = 1024;			# 1024 byte blocks
$Types{'3'} = 2048;			# 2048 byte blocks
$Types{'4'} = 4096;			# 4096 byte blocks
$Types{'5'} = 8192;			# 8192 byte blocks

#
# Required arguments are
#	block device name
#
&Usage if ( ! defined($ARGV[0]) );
$Device = $ARGV[0];
#
# check to see if it is a valid device, and it exists
#
&Error("ENFILE") if ( ! -e $Device );
&Error("ENBLK") if ( ! -b $Device );
&Error("ENOPERM") if ( ! -r $Device );
#
# open the named device
#
open( FS, "$Device" );
#
# seek in 512 bytes.  This is the empty space which used to contain boot
# code (a long time ago).
#
seek( FS, 512, 0 );
#
# read the superblock, which is typically 512 bytes in size
#
read( FS, $buf, 512 );
#
# unpack it into the structure
# This piece of code may be system dependant - based upon the potentially
# different structures available
#
( $s_isize, $s_fsize, $s_nfree, $s_free, $s_ninode, $s_inode, 
  $s_flock, $s_ilock, $s_fmod, $s_ronly, $s_time, $s_dev, $s_tfree, 
  $s_tinode, $s_fname, $s_pack, $s_fill, $s_state, $s_magic, 
  $s_type ) = unpack( $S51K, $buf );
#
# unpack the free block list into an array
#
(@s_free)  = unpack($S51K_s_free,  $s_free);
#
# and now the free inode list
#
(@s_inode) = unpack($S51K_s_inode, $s_inode);
#
# calculate the Blocksize, which is typically mulitples of 512 bytes
#
$bsize = $Types{$s_type};
#
# now put a real word in for the superblock modified flag
#
if ( $s_fmod == 0 )
   {
   $s_fmod = "No";
   }
else
   {
   $s_fmod = "Yes";
   }
#
# OK, and now for the filesystem mounted read-only flag
#
if ( $s_ronly == 0 )
   {
   $s_ronly = "No";
   }
else
   {
   $s_ronly = "Yes";
   }
#
# print a report
#
printf "Filesystem Information for %s\n\n", $Device;
printf "Volumne Name : %6s          Pack Name : %6s\n", $s_fname, $s_pack;
printf "File System Block Size                  : %4d bytes\n", $bsize;
printf "Total size of Volume (%4d byte blocks) : %ld\n", $bsize, $s_fsize;
printf "Total size of i-list (%4d byte blocks) : %u\n", $bsize, $s_isize;
printf "Total Free Blocks    (%4d byte blocks) : %ld\n", $bsize, $s_tfree;
printf "Total Free Inodes                       : %ld\n", $s_tinode;
printf "Has the superblock been modified?       : %s\n", $s_fmod;
printf "Is the filesystem mounted read only?    : %s\n", $s_ronly;
printf "Last superblock update at               : %s\n\n\n", &ctime($s_time);;
printf "Number of blocks in the free list : %ld   Maximum : %ld\n", 
	$s_nfree, $NICFREE;
printf "Current Free Block List reads : \n";
&PrintFreeBlockList;

printf "\nNumber of inodes in the free list : %ld   Maximum : %ld\n", 
	$s_ninode, $NICINOD;
printf "Current Free Inode List reads : \n";
&PrintFreeInodeList;
exit(0);

#
# The PrintFreeBlockList subroutine will read through the global variable
# $s_free printing five block addresses per line, with a prefix of
# a###: where ### is the entry number in the list
#
sub PrintFreeBlockList
{
   #
   # loop through the list starting a zero, and going to the actial number
   # stored in the superblock
   #
   for ( $z = 0; $z < $s_nfree; $z+=5 )
	  {
	  #
	  # print five per line, and then do a line feed.
	  #
      for ( $y = $z; $y < $z + 5; $y++ )
	     {
         if ( $y < $s_nfree )
			{
            printf "a%02d:%10ld ",$y, $s_free[$y];
			}
	     }
	  printf "\n";
	  }
}

#
# The PrintFreeInodeList subroutine will read through the global variable
# $s_inode printing five inode addresses per line, with a prefix of
# i###: where ### is the entry number in the list
#
sub PrintFreeInodeList
{
   #
   # loop through the list starting a zero, and going to the actial number
   # stored in the superblock
   #
   for ( $z = 0; $z < $s_ninode; $z+=5 )
	  {
	  #
	  # print five per line, and then do a line feed.
	  #
      for ( $y = $z; $y < $z + 5; $y++ )
	     {
         if ( $y < $s_ninode )
			{
            printf "i%02d:%10ld ",$y, $s_inode[$y];
			}
	     }
	  printf "\n";
	  }
}

#
# the Error subroutine will explain to the user what he/she/it did wrong.
# Possible errors are
#		not a block device (ENBLK)
#		file doesn't exist (ENFILE)
#		no permissions (ENOPERM)
#
sub Error
{
   local( $msg ) = @_;
   if ( $msg eq "ENFILE" )
	  {
	  printf "The specified device file does not exist.\n";
	  &Usage;
	  }
   if ( $msg eq "ENBLK" )
	  {
	  printf "The specified device file is not a block special file.\n";
	  &Usage;
	  }
   if ( $msg eq "ENOPERM" )
	  {
	  printf "Sorry, insufficient priveledges.\n";
      exit(1);
	  }
}

#
# the usage subroutine will give the command usage
#
sub Usage
{
   printf "Usage : fs.pl block_device\n";
   exit(1);
}

#
# the ctime subroutine here is a modified version of that provided with the
# PERL distribution
#
# Original Author Waldemar Kebsch, Federal Republic of Germany, November 1988
# Modified by Marion Hakanson (hakanson@cse.ogi.edu)
# Modified by Chris Hare (chare@choreo.ca)

sub ctime {

    @DoW = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
    @MoY = ('Jan','Feb','Mar','Apr','May','Jun',
	    'Jul','Aug','Sep','Oct','Nov','Dec');

    local($time) = @_;
    local($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);

    # Determine what time zone is in effect.
    # Use GMT if TZ is defined as null, local time if TZ undefined.
    # There's no portable way to find the system default timezone.

    $TZ = defined($ENV{'TZ'}) ? ( $ENV{'TZ'} ? $ENV{'TZ'} : 'GMT' ) : '';
    ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
        ($TZ eq 'GMT') ? gmtime($time) : localtime($time);

    # Hack to deal with 'PST8PDT' format of TZ
    # Note that this can't deal with all the esoteric forms, but it
    # does recognize the most common: [:]STDoff[DST[off][,rule]]

    if($TZ=~/^([^:\d+\-,]{3,})([+-]?\d{1,2}(:\d{1,2}){0,2})([^\d+\-,]{3,})?/){
        $TZ = $isdst ? $4 : $1;
    }
    $TZ .= ' ' unless $TZ eq '';

    $year += ($year < 70) ? 2000 : 1900;
    sprintf("%s %s %2d %2d:%02d:%02d %s%4d",
      $DoW[$wday], $MoY[$mon], $mday, $hour, $min, $sec, $TZ, $year);
}


#
# we won't execute this
#
printf "BUSTER!\n";

