/* RDB-Informer V0.2
 * Prints out information stored in the Rigid Disk Block of a device
 *
 * Written with MEmacs in September 1994 by
 *
 *               v
 *     David Balazic
 *     v
 *     Centiba 39
 *     69220 Lendava
 *     Slovenija
 *
 * This program is FreeWare.
 * You may spread it as you like, but leave my name noticed.
 *
 * Usage :
 * > RDB-Informer [[DEVICE] <device>] [[UNIT] <unit-nr>]
 *
 * The default for DEVICE is 'scsi.device' and for UNIT '0'
 *
 * Examples :
 * > RDB-Informer scsi.device unit 4
 * > RDB-Informer gvpscsi.device unit 6
 * > RDB-Informer unit 2                ; uses scsi.device unit 2
 * > RDB-Informer evolution.device      ; uses evolution.device unit 0
 *
 */


#include <clib/exec_protos.h>
#include <clib/dos_protos.h>

#include <devices/trackdisk.h>
#include <devices/hardblocks.h>
#include <dos/filehandler.h>
#include <dos/rdargs.h>

int OpenLibs(void);
void CloseLibs(void);
int OpenDev(void);
void CloseDev(void);
int ReadRDB(void);
void ParseRDB(void);
void PrintRDBFlags(ULONG);
char *getstr(char *,char *,int);
int SumOK(ULONG *);
void ParseBADB(ULONG);
void ParsePART(ULONG);
void ParseFSHD(ULONG);
void ParseDINI(ULONG);
ULONG countBB(void);
int readblok(ULONG *,ULONG,ULONG);
char *BSTR2CSTR(UBYTE *,char *);
void PrintPARTFlags(ULONG);
void PrintPARTEnvironment(ULONG *);
int countlen(ULONG);
void partend(ULONG,int);
void badend(ULONG,int);
void fsend(ULONG,int);

struct DosLibrary *DOSBase;
struct MsgPort *DevicePort;
struct IOExtTD *scsiIO;
struct RigidDiskBlock RDB;
struct BadBlockBlock BBB;
struct PartitionBlock PB;
struct FileSysHeaderBlock FHB;
struct LoadSegBlock LSB;
struct RDArgs *args;

LONG argarray[]= {(LONG)"scsi.device",(LONG)NULL};
int scsiopen;
int RDBblok;
char cbf[256];
ULONG countbytes,countblocks;
STRPTR verstring="\0$VER: RDB-Informer 0.2 (30.09.94)\x0a\x0d\0";

main()
{
LONG unitx=0;
argarray[1]=(LONG)&unitx;
 if(OpenLibs())
 {
  if(args=ReadArgs("DEVICE,UNIT/N",argarray,NULL))
  {
   if(OpenDev())
   {
    if(ReadRDB())
    {
     ParseRDB();
    }else Printf("Rigid Disk Block of '%s' unit %ld not found.\n",argarray[0],*(LONG *)argarray[1]);
   }else Printf("Can't open '%s' unit %ld!\n",argarray[0],*(LONG *)argarray[1]);
  FreeArgs(args);
  }else Printf("error in arguments\n");
 CloseDev();
 }else Printf("Can't open 'dos.library' version 36 !!!\n");
 CloseLibs();
}

int OpenLibs(void)
{
if( ! (DOSBase = (struct DosLibrary *) OpenLibrary(DOSNAME,36L) ) ) return FALSE;
return TRUE;
}

void CloseLibs(void)
{
if (DOSBase) CloseLibrary((struct Library *)DOSBase);
}

int OpenDev(void)
{
if (DevicePort=CreateMsgPort())
{
 if(scsiIO=CreateIORequest(DevicePort,sizeof(struct IOExtTD)))
 {
  if(!OpenDevice((STRPTR)argarray[0],*((ULONG *)(argarray[1])),(struct IORequest *)scsiIO,0))
  {
   scsiopen=TRUE;
   return TRUE;
  }
 }
}
scsiopen=FALSE;
return FALSE;
}

void CloseDev(void)
{
if(scsiopen)   CloseDevice((struct IORequest *)scsiIO);
if(scsiIO)     DeleteIORequest(scsiIO);
if(DevicePort) DeleteMsgPort(DevicePort);
}

int ReadRDB(void)
{
 UBYTE buf[512];
 int RDBfound=FALSE;
 int blok=0,part=0;

 do
 {
  scsiIO->iotd_Req.io_Command=CMD_READ;
  scsiIO->iotd_Req.io_Flags=0;
  scsiIO->iotd_Req.io_Data=buf;
  scsiIO->iotd_Req.io_Length=512;
  scsiIO->iotd_Req.io_Offset=blok<<TD_SECSHIFT;

  DoIO((struct IORequest *)scsiIO);
  RDBblok=blok;
  if( ((struct RigidDiskBlock)buf).rdb_ID==IDNAME_RIGIDDISK )
   RDBfound=TRUE;
  blok++;
  if(blok>RDB_LOCATION_LIMIT)break;
 } while(!(RDBfound));

 if(RDBfound)
 {
  CopyMem(buf,&RDB,256);
  return TRUE;
 }else return FALSE;
}

void ParseRDB(void)
{
Printf("Hard-blocks information of '%s' unit %ld\n\n",argarray[0],*(LONG *)argarray[1]);
Printf("Rigid Disk Block found at block %ld",RDBblok);
if(SumOK((ULONG *)&RDB)){
Printf("  ---  CheckSum is OK.\n\n");
Printf(" ID           = $%08lx = '%lc%lc%lc%lc'     block identifier\n",RDB.rdb_ID,
     ( RDB.rdb_ID&0xff000000)>>24,(RDB.rdb_ID&0xff0000)>>16,
     ( RDB.rdb_ID&0xff00)>>8,     (RDB.rdb_ID&0xff)   );

Printf(" SummedLongs  = $%08lx = %10ld size of RDB structure\n",RDB.rdb_SummedLongs,RDB.rdb_SummedLongs);
Printf(" ChkSum       = $%08lx = %10ld block checksum\n",RDB.rdb_ChkSum,RDB.rdb_ChkSum);
Printf(" HostID       = $%08lx = %10ld SCSI Target ID of host(controller)\n",RDB.rdb_HostID,RDB.rdb_HostID);
Printf(" BlockBytes   = $%08lx = %10ld size of disk blocks\n",RDB.rdb_BlockBytes,RDB.rdb_BlockBytes);
PrintRDBFlags(RDB.rdb_Flags);

Printf("\n --- Block list heads ($FFFFFFFF or -1 is none):\n");
Printf(" BadBlockList      = $%08lx = %10ld optional bad block list\n",RDB.rdb_BadBlockList,RDB.rdb_BadBlockList);
Printf(" PartitionList     = $%08lx = %10ld optional first partition block\n",RDB.rdb_PartitionList,RDB.rdb_PartitionList);
Printf(" FileSysHeaderList = $%08lx = %10ld optional file system header block\n",RDB.rdb_FileSysHeaderList,RDB.rdb_FileSysHeaderList);
Printf(" DriveInit         = $%08lx = %10ld optional drive-specific init code\n",RDB.rdb_DriveInit,RDB.rdb_DriveInit);

Printf("\n --- Physical drive characteristics:\n");
Printf(" Cylinders    = $%08lx = %10ld number of drive cylinders\n",RDB.rdb_Cylinders,RDB.rdb_Cylinders);
Printf(" Sectors      = $%08lx = %10ld sectors per track\n",RDB.rdb_Sectors,RDB.rdb_Sectors);
Printf(" Heads        = $%08lx = %10ld number of drive heads\n",RDB.rdb_Heads,RDB.rdb_Heads);
Printf(" Interleave   = $%08lx = %10ld interleave\n",RDB.rdb_Interleave,RDB.rdb_Interleave);
Printf(" Park         = $%08lx = %10ld landing zone cylinder\n",RDB.rdb_Park,RDB.rdb_Park);
Printf(" WritePreComp = $%08lx = %10ld starting cylinder: write precompensation\n",RDB.rdb_WritePreComp,RDB.rdb_WritePreComp);
Printf(" ReducedWrite = $%08lx = %10ld starting cylinder: reduced write current\n",RDB.rdb_ReducedWrite,RDB.rdb_ReducedWrite);
Printf(" StepRate     = $%08lx = %10ld drive step rate\n",RDB.rdb_StepRate,RDB.rdb_StepRate);

Printf("\n --- Logical drive characteristics\n");
Printf(" RDBBlocksLo     = $%08lx = %10ld\n    low block of range reserved for these hardblocks\n",RDB.rdb_RDBBlocksLo,RDB.rdb_RDBBlocksLo);
Printf(" RDBBlocksHi     = $%08lx = %10ld\n    high block of range reserved for these hardblocks\n",RDB.rdb_RDBBlocksHi,RDB.rdb_RDBBlocksHi);
Printf(" LoCylinder      = $%08lx = %10ld\n    low cylinder of partitionable disk area\n",RDB.rdb_LoCylinder,RDB.rdb_LoCylinder);
Printf(" HiCylinder      = $%08lx = %10ld\n    high cylinder of partitionable disk are\n",RDB.rdb_HiCylinder,RDB.rdb_HiCylinder);
Printf(" CylBlocks       = $%08lx = %10ld number of blocks per cylinder\n",RDB.rdb_CylBlocks,RDB.rdb_CylBlocks);
Printf(" AutoParkSeconds = $%08lx = %10ld zero means no autopark\n",RDB.rdb_AutoParkSeconds,RDB.rdb_AutoParkSeconds);
Printf(" HighRDSKBlock   = $%08lx = %10ld highest block used by RDB\n",RDB.rdb_HighRDSKBlock,RDB.rdb_HighRDSKBlock);

Printf("\n --- Drive identification\n");
Printf(" - Disk identification :");
if ( RDB.rdb_Flags & RDBFF_DISKID)
{
 Printf("\n DiskVendor        = '%s'\n",getstr(RDB.rdb_DiskVendor,cbf,8));
 Printf(  " DiskProduct       = '%s'\n",getstr(RDB.rdb_DiskProduct,cbf,16));
 Printf(  " DiskRevision      = '%s'\n",getstr(RDB.rdb_DiskRevision,cbf,4));
}else Printf(" *** not avaliable.\n");
Printf("\n");
Printf(" - Controller identification :");
if ( RDB.rdb_Flags & RDBFF_CTRLRID)
{
 Printf("\n ControllerVendor  = '%s'\n",getstr(RDB.rdb_ControllerVendor,cbf,8));
 Printf(  " ControllerProduct = '%s'\n",getstr(RDB.rdb_ControllerProduct,cbf,16));
 Printf(  " ControllerRevision= '%s'\n",getstr(RDB.rdb_ControllerRevision,cbf,4));
}else Printf("\n *** not avaliable.\n");
Printf("\n");
if(RDB.rdb_BlockBytes!=512)
{
 Printf("*** Block sizes other than 512 bytes not supported !!");
 return;
}
if(RDB.rdb_BadBlockList!=0xffffffff) ParseBADB(RDB.rdb_BadBlockList);
if(RDB.rdb_PartitionList!=0xffffffff) ParsePART(RDB.rdb_PartitionList);
if(RDB.rdb_FileSysHeaderList!=0xffffffff) ParseFSHD(RDB.rdb_FileSysHeaderList);
if(RDB.rdb_DriveInit!=0xffffffff) ParseDINI(RDB.rdb_DriveInit);
}
else
 Printf("\n   *** CheckSum error !!\n");

}

void PrintRDBFlags(ULONG flags)
{
Printf(" Flags        = $%08lx =\n",flags);

if (flags & RDBFF_LAST)
Printf("                RDBF_LAST       - Last drive on this controller\n");
if (flags & RDBFF_LASTLUN)
Printf("                RDBF_LASTLUN    - Last LUN on this SCSI-address\n");
if (flags & RDBFF_LASTTID)
Printf("                RDBF_LASTTID    - Last SCSI-address on this SCSI bus\n");
if (flags & RDBFF_NORESELECT)
Printf("                RDBF_NORESELECT - Does not support scsi reselection\n");
else
Printf("                                - Drive supports scsi reselection\n");
if (flags & RDBFF_DISKID)
Printf("                RDBF_DISKID     - RDB contains valid disk identification\n");
if (flags & RDBFF_CTRLRID)
Printf("                RDBF_CTRLRID    - RDB contains valid controller identification\n");
if (flags & RDBFF_SYNCH)
Printf("                RDBF_SYNCH      - Drive supports scsi synchronous mode\n");
if ( flags & ~(RDBFF_LAST|RDBFF_LASTLUN|RDBFF_LASTTID|RDBFF_NORESELECT|RDBFF_DISKID|RDBFF_CTRLRID|RDBFF_SYNCH))
Printf("                *** some unknown flags !!!!\n");
}

char *getstr(char *from,char *to,int nr)
{
int cn=0;
while ( ((to[cn]=from[cn])!=0)&&((cn+1)<nr)) cn++;
to[cn+1]=0;
return to;
}

int SumOK(ULONG *p)
{
int i;
LONG chk=0;
ULONG nr=((struct RigidDiskBlock *)p)->rdb_SummedLongs;

if(nr>555) return FALSE;

for(i=0;i<nr;i++)
   chk+=(*p++);
if (chk) return FALSE;
return TRUE;
}

void ParseBADB(ULONG BADBblok)
{
 int res,blokerr=0;
 ULONG bnr,allbad=0;
 do
 {
  Printf("Bad Block Block at block %ld",BADBblok);
  res=readblok((ULONG *)&BBB,BADBblok,IDNAME_BADBLOCK);
  if(res==1){Printf("\n   *** Wrong block ID !!\n");badend(allbad,1);return;}
  if(res==2){Printf("\n   *** CheckSum error !!\n");badend(allbad,1);return;}
  if(res==3){Printf("\n   *** Read error !!\n");badend(allbad,1);return;}
  if(res==0)
  {
   Printf("  ---  CheckSum is OK.\n\n");
   bnr=countBB();
   allbad+=bnr;
   Printf(" This Bad Block Block contains %ld Bad Block replacements\n",bnr);
   BADBblok=BBB.bbb_Next;
  }
  else
  {
   badend(allbad,1);
   return;
  }
 }while(BADBblok!=0xffffffff);
 badend(allbad,0);
}

void badend(ULONG bad,int err)
{
 if(err)
 Printf("*** There are some errors in Bad Block Blocks !!!\n");
 Printf("There are total %ld valid Bad Block Replacements.\n\n",bad);
}

int readblok(ULONG *buf,ULONG blkn,ULONG ident)
{
 scsiIO->iotd_Req.io_Command=CMD_READ;
 scsiIO->iotd_Req.io_Flags=0;
 scsiIO->iotd_Req.io_Data=buf;
 scsiIO->iotd_Req.io_Length=512;
 scsiIO->iotd_Req.io_Offset=blkn<<TD_SECSHIFT;

 DoIO((struct IORequest *)scsiIO);
 if(scsiIO->iotd_Req.io_Error==0)
 {
  if( ((struct RigidDiskBlock *)buf)->rdb_ID==ident )
  {
   if(SumOK(buf))
    return 0;
   return 2;
  }
  else return 1;
 }
 else return 3;
}

ULONG countBB(void)
{
 int c;
 ULONG cnt=0;
 for(c=0; (c<61)&&( ( ( ( &(BBB.bbb_BlockPairs[c]) ) - (&BBB) )>>2) < BBB.bbb_SummedLongs);c++)
  if(BBB.bbb_BlockPairs[c].bbe_BadBlock!=0xffffffff)
   cnt++;
 return cnt;
}

void ParsePART(ULONG PARTblok)
{
 int res;
 ULONG allpart=0;
 do
 {
  Printf("Partition Block at block %ld",PARTblok);
  res=readblok((ULONG *)&PB,PARTblok,IDNAME_PARTITION);
  if(res==1){Printf("\n   *** Wrong block ID !!\n");partend(allpart,1);return;}
  if(res==2){Printf("\n   *** CheckSum error !!\n");partend(allpart,1);return;}
  if(res==3){Printf("\n   *** Read error !!\n");partend(allpart,1);return;}
  if(res==0)
  {
   allpart++;
   Printf("  ---  CheckSum is OK.\n");
   Printf(" Partition %s:\n",BSTR2CSTR(PB.pb_DriveName,cbf));
   PrintPARTFlags(PB.pb_Flags);
   Printf(" DevFlags       = $%08lx = %10ld Preferred flags for OpenDevice\n",PB.pb_DevFlags,PB.pb_DevFlags);
   PrintPARTEnvironment(PB.pb_Environment);
   Printf("\n");
   PARTblok=PB.pb_Next;
  }
  else
  {
   partend(allpart,1);
  }
 }while(PARTblok!=0xffffffff);
 partend(allpart,0);
}

void partend(ULONG parts,int err)
{
 if(err)
 Printf("*** There are some errors in Partition Blocks !!!\n");
 Printf("There are total %ld valid partitions on this drive.\n\n",parts); 
}



char *BSTR2CSTR(UBYTE *bstr,char* buf)
{
return getstr( (char *)(((ULONG)bstr)+1),buf,bstr[0]);
}

void PrintPARTFlags(ULONG flags)
{
Printf(" Flags          = $%08lx =\n",flags);

if (flags & PBFF_BOOTABLE)
Printf("                  PBF_BOOTABLE    - Partition is bootable\n");
else
Printf("                                  - Partition is not bootable\n");
if (flags & PBFF_NOMOUNT)
Printf("                  PBF_NOMOUNT     - Partition is not automaticaly mounted \n");
else
Printf("                                  - Partition is automaticaly mounted\n");
if ( flags & ~(PBFF_BOOTABLE|PBFF_NOMOUNT))
Printf("                   *** some unknown flags !!!!\n");
}

void PrintPARTEnvironment(ULONG *inp)
{
struct DosEnvec *DE=(struct DosEnvec *)inp;
ULONG siz=DE->de_TableSize;
ULONG i=0;

Printf(" DosEnvec block with %ld entries\n",siz);

Printf(" SizeBlock      = $%08lx = %10ld block size in longwords\n",DE->de_SizeBlock,DE->de_SizeBlock);
i++;
if(i>=siz)return;
Printf(" SecOrg         = $%08lx = %10ld not used\n",DE->de_SecOrg,DE->de_SecOrg);
i++;
if(i>=siz)return;
Printf(" Surfaces       = $%08lx = %10ld number of heads\n",DE->de_Surfaces,DE->de_Surfaces);
i++;
if(i>=siz)return;
Printf(" SectorPerBlock = $%08lx = %10ld not used; must be 1\n",DE->de_SectorPerBlock,DE->de_SectorPerBlock);
i++;
if(i>=siz)return;
Printf(" BlocksPerTrack = $%08lx = %10ld number of blocks per track\n",DE->de_BlocksPerTrack,DE->de_BlocksPerTrack);
i++;
if(i>=siz)return;
Printf(" Reserved       = $%08lx = %10ld DOS reserved blocks at start of partition\n",DE->de_Reserved,DE->de_Reserved);
i++;
if(i>=siz)return;
Printf(" PreAlloc       = $%08lx = %10ld DOS reserved blocks at end of partition\n",DE->de_PreAlloc,DE->de_PreAlloc);
i++;
if(i>=siz)return;
Printf(" Interleave     = $%08lx = %10ld (usually 0)\n",DE->de_Interleave,DE->de_Interleave);
i++;
if(i>=siz)return;
Printf(" LowCyl         = $%08lx = %10ld starting cylinder\n",DE->de_LowCyl,DE->de_LowCyl);
i++;
if(i>=siz)return;
Printf(" HighCyl        = $%08lx = %10ld ending cylinder\n",DE->de_HighCyl,DE->de_HighCyl);
i++;
if(i>=siz)return;
Printf(" NumBuffers     = $%08lx = %10ld initial number of buffers\n",DE->de_NumBuffers,DE->de_NumBuffers);
i++;
if(i>=siz)return;
Printf(" BufMemType     = $%08lx = %10ld type of memory for buffers\n",DE->de_BufMemType,DE->de_BufMemType);
i++;
if(i>=siz)return;
Printf(" MaxTransfer    = $%08lx = %10ld max number of bytes to transfer at a time\n",DE->de_MaxTransfer,DE->de_MaxTransfer);
i++;
if(i>=siz)return;
Printf(" Mask           = $%08lx = %10ld address mask to block out certain memory\n",DE->de_Mask,DE->de_Mask);
i++;
if(i>=siz)return;
Printf(" BootPri        = $%08lx = %10ld boot priority for autoboot\n",DE->de_BootPri,DE->de_BootPri);
i++;
if(i>=siz)return;
Printf(" DosType        = $%08lx = '%lc%lc%lc%lc'     HEX string showing filesystem type\n",DE->de_DosType,
     ( DE->de_DosType&0xff000000)>>24,(DE->de_DosType&0xff0000)>>16,
     ( DE->de_DosType&0xff00)>>8,     (DE->de_DosType&0xff)   );
i++;
if(i>=siz)return;
Printf(" Baud           = $%08lx = %10ld baud rate for serial handler\n",DE->de_Baud,DE->de_Baud);
i++;
if(i>=siz)return;
Printf(" Control        = $%08lx = %10ld control word for handler/filesystem\n",DE->de_Control,DE->de_Control);
i++;
if(i>=siz)return;
Printf(" BootBlocks     = $%08lx = %10ld number of blocks containing boot code\n",DE->de_BootBlocks,DE->de_BootBlocks);
i++;
if(i>=siz)return;
Printf(" *** %ld unknown entries !!\n",siz-i);
}



void ParseFSHD(ULONG FSHDblok)
{
 int res;
 ULONG allfs=0;

 do
 {
  Printf("File System Header Block at block %ld",FSHDblok);
  res=readblok((ULONG *)&FHB,FSHDblok,IDNAME_FILESYSHEADER);
  if(res==1){Printf("\n   *** Wrong block ID !!\n");fsend(allfs,1);return;}
  if(res==2){Printf("\n   *** CheckSum error !!\n");fsend(allfs,1);return;}
  if(res==3){Printf("\n   *** Read error !!\n");fsend(allfs,1);return;}
  if(res==0)
  {
   allfs++;
   Printf("  ---  CheckSum is OK.\n\n");
   countbytes=countblocks=0;
   if(countlen(FHB.fhb_SegListBlocks))
   {
    Printf(" Size      = $%08lx = %10ld bytes\n",countbytes,countbytes);
    Printf(" Size      = $%08lx = %10ld blocks\n",countblocks,countblocks);
    Printf(" Flags     = $%08lx = ?????\n",FHB.fhb_Flags);
    Printf(" DosType   = $%08lx = '%lc%lc%lc%lc'\n",FHB.fhb_DosType,
           ( FHB.fhb_DosType&0xff000000)>>24,(FHB.fhb_DosType&0xff0000)>>16,
           ( FHB.fhb_DosType&0xff00)>>8,     (FHB.fhb_DosType&0xff)   );
    Printf(" Version   = $%08lx = %5ld.%-5ld release version of this code\n",
           FHB.fhb_Version,(FHB.fhb_Version&0xffff0000)>>16,FHB.fhb_Version&0xffff);
    Printf(" PatchFlags= $%08lx = ?????\n",FHB.fhb_PatchFlags);
    Printf(" Type      = $%08lx = %10ld device node type : zero\n",FHB.fhb_Type,FHB.fhb_Type);
    Printf(" Task      = $%08lx = %10ld DOS task field : zero\n",FHB.fhb_Task,FHB.fhb_Task);
    Printf(" Lock      = $%08lx = %10ld not used for devices : zero\n",FHB.fhb_Lock,FHB.fhb_Lock);
    Printf(" Handler   = $%08lx = %10ld filename to loadseg : zero placeholder\n",FHB.fhb_Handler,FHB.fhb_Handler);
    Printf(" StackSize = $%08lx = %10ld stacksize to use when starting task\n",FHB.fhb_StackSize,FHB.fhb_StackSize);
    Printf(" Priority  = $%08lx = %10ld task priority when starting task\n",FHB.fhb_Priority,FHB.fhb_Priority);
    Printf(" Startup   = $%08lx = %10ld startup message : zero placeholder\n",FHB.fhb_Startup,FHB.fhb_Startup);
    Printf(" SegListBlocks=$%08lx=%10ld linked list of LoadSegBlocks\n",FHB.fhb_SegListBlocks,FHB.fhb_SegListBlocks);
    Printf(" GlobalVec = $%08lx = %10ld BCPL global vector when starting task\n",FHB.fhb_GlobalVec,FHB.fhb_GlobalVec);
    Printf(" Res2[0]   = $%08lx              reserved\n",FHB.fhb_Reserved2[0]);
    Printf(" Res2[1]   = $%08lx              reserved\n",FHB.fhb_Reserved2[1]);
    Printf(" Res2[2]   = $%08lx              reserved\n",FHB.fhb_Reserved2[2]);
    Printf("\n");
   }
  FSHDblok=FHB.fhb_Next;
  }
  else
  {
   fsend(allfs,1);
   return;
  }
 }while(FSHDblok!=0xffffffff);
 fsend(allfs,0);
}

void fsend(ULONG fs,int err)
{
 if(err)
 Printf("*** There are some errors in File System Header Blocks !!!\n");
 Printf("There are total %ld valid file systems stored on this drive.\n\n",fs);
}

int countlen(ULONG LSEGblok)
{
 int res;

 do
 {
  res=readblok((ULONG *)&LSB,LSEGblok,IDNAME_LOADSEG);
  if(res==1)
  {
   Printf("   *** Wrong block ID at block %ld.\n",LSEGblok);
   Printf("   *** Expected LoadSegBlock (ID='LSEG'). Got ID = '%lc%lc%lc%lc'.\n",
       ( RDB.rdb_ID&0xff000000)>>24,(RDB.rdb_ID&0xff0000)>>16,
       ( RDB.rdb_ID&0xff00)>>8,     (RDB.rdb_ID&0xff)   );
   return FALSE;
  }
  if(res==2)
  {
   Printf("   *** CheckSum error in block %ld (LoadSegBlock).\n",LSEGblok);
   return FALSE;
  }
  if(res==3)
  {
   Printf("   *** Read error at block %ld (LoadSegBlock) !!\n");return FALSE;
  }
  if(res==0)
  {
   countblocks++;
   countbytes+=(LSB.lsb_SummedLongs<<2)
               -
               (ULONG) &(((struct LoadSegBlock *)0L)->lsb_LoadData[0]);
   LSEGblok=LSB.lsb_Next;
  }
  else
   return FALSE;
 }while(LSEGblok!=0xffffffff);
 return TRUE;
}


void ParseDINI(ULONG DINIblok)
{
 int res;

 Printf("Dive Init Code starting at block %ld\n",DINIblok);
 countbytes=countblocks=0;
 if(countlen(DINIblok))
 {
  Printf(" Size      = $%08lx = %10ld bytes\n",countbytes,countbytes);
  Printf(" Size      = $%08lx = %10ld blocks\n",countblocks,countblocks);
 }
}

