/*
**	$RCSfile: VDStat.c,v $
**	$Filename: VDStat.c $
**	$Revision: 3.0 $
**	$Date: 2001/08/19 16:32:10 $
**
**	vdisk.device support command VDStat (version 3.5)
**	
**	(C) Copyright 1993-2003 by Etienne Vogt
*/

#include <exec/io.h>
#include <exec/alerts.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/filehandler.h>
#include <dos/rdargs.h>
#include <workbench/startup.h>
#define __USE_SYSBASE
#include <proto/exec.h>
#include <proto/dos.h>
#include <string.h>
#include <stdlib.h>
#include "vdisk.h"

struct VD_Dev	*VDiskBase;
struct ExecBase *SysBase;
static struct RDArgs *myrda;
static struct WBStartup *wbmsg;
static struct IORequest vdio;

static ULONG __saveds main(void);
static void clearall(void);
STRPTR VD_RecErrTxt(ULONG vde_code);
#ifdef __SASC
void __regargs __chkabort(void);
#endif

static UBYTE template[] = "DEVICE,UNIT/K/N,FULL/S";
static UBYTE version[] = "$VER: VDStat 3.5 (15.2.2003)";

#define OPT_DEVICE	0
#define OPT_UNIT	1
#define OPT_FULL	2
#define OPTMAX		3


static ULONG __saveds main(void)	/* No startup code */
{
  struct Process *myproc;
  LONG opts[OPTMAX];

  LONG unit = 0, error;
  ULONG rc = 0;
  STRPTR errormsg;
  struct VDU_Unit *unitptr;

  SysBase = *(struct ExecBase **)4;
  DOSBase = NULL;
  VDiskBase = NULL;
  wbmsg = NULL;
  myrda = NULL;

  myproc = (struct Process *)FindTask(NULL);
  if ((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37)) == NULL)
  { Alert(AT_Recovery|AG_OpenLib|AO_DOSLib);
    clearall();
    return(100);
  }

  if (!(myproc->pr_CLI))		/* If started from WB, exit cleanly */
  { WaitPort(&(myproc->pr_MsgPort));
    wbmsg = (struct WBStartup *)GetMsg(&(myproc->pr_MsgPort));
    clearall();
    return(20);
  }
  else
  { memset((char *)opts, 0, sizeof(opts));
    if ((myrda = ReadArgs(template, opts, NULL)) == NULL)
    { PrintFault(IoErr(),NULL);
      clearall();
      return(20);
    }
    if (opts[OPT_UNIT]) 
    { unit = *(ULONG *)opts[OPT_UNIT];
      if (unit < 0 || unit >= VD_NUMUNITS)
      { Printf("Invalid unit number %ld\n", unit);
        clearall();
        return(20);
      }
    }
    if (opts[OPT_DEVICE])
    {
      UBYTE  *colon;
      struct DosList  *dlist;
      struct FileSysStartupMsg  *vdstartup;
      STRPTR fssmdev;

      unit = -1;
      if (colon = (UBYTE *)strchr((const char *)opts[OPT_DEVICE],':')) *colon = (UBYTE)0;
      dlist = LockDosList(LDF_DEVICES|LDF_READ);
      if (dlist = FindDosEntry(dlist,(STRPTR)opts[OPT_DEVICE],LDF_DEVICES))
      { vdstartup = BADDR(((struct DeviceNode *)dlist)->dn_Startup);
        fssmdev = (UBYTE *)BADDR(vdstartup->fssm_Device) + 1;
        if (TypeOfMem(fssmdev) && !strcmp((const char *)fssmdev, VD_NAME)) unit = vdstartup->fssm_Unit;
        else errormsg = "Device %s is not a vdisk unit\n";
      }
      else errormsg = "Device %s is not mounted\n";
      UnLockDosList(LDF_DEVICES|LDF_READ);
    }
    if (unit == -1)
    { Printf(errormsg, (STRPTR)opts[OPT_DEVICE]);
      clearall();
      return(20);
    }
    FreeArgs(myrda);
    myrda = NULL;
  }

  if ((error = OpenDevice(VD_NAME, -1L, &vdio, 0L)) == 0)
  { VDiskBase = (struct VD_Dev *)vdio.io_Device;
    if (unitptr = VDiskBase->vd_Root->vdr_Units[unit])
    { if (opts[OPT_FULL])
      { Printf("VDiskBase address: %08lx\n", (ULONG)VDiskBase);
	Printf("Root structure address: %08lx\n", (ULONG)VDiskBase->vd_Root);
	Printf("Unit structure address: %08lx\n", (ULONG)unitptr);
	Printf("Operations completed: %lu\n", unitptr->vdu_IOCount);
	Printf("Cleaning count: %lu\n", unitptr->vdu_CleanCount);
	Printf("Number of VTracks: %lu\n", (ULONG)unitptr->vdu_NumTracks);
	Printf("Root Track number: %lu\n", (ULONG)unitptr->vdu_RootTrack);
	Printf("Boot Priority: %ld\n", (ULONG)unitptr->vdu_Priority);
	Printf("FileSystem DOSType: %08lx\n", unitptr->vdu_DOSType);
	Printf("Physical Sector Size: %lu [%lu]\n", (ULONG)unitptr->vdu_SectorSize, (ULONG)unitptr->vdu_SecSizeLog);
	Printf("RootBlock Key ID: %lu\n", unitptr->vdu_RootKey);
	Printf("AmigaDOS High Cylinder: %lu\n", unitptr->vdu_DosHighCyl);
	Printf("AmigaDOS Surfaces: %lu\n", unitptr->vdu_DosSurfaces);
	Printf("AmigaDOS Sectors Per Track: %lu\n", unitptr->vdu_DosSectPerTrack);
	Printf("AmigaDOS Device Name: %s\n", &unitptr->vdu_DosName);
	Printf("Unit flags: ");
	if (unitptr->vdu_Flags & VDUF_VALID) Printf(" VALID,");
	if (unitptr->vdu_Flags & VDF_AUTOCLEAN) Printf(" AUTOCLEAN,");
	if (unitptr->vdu_Flags & VDF_ALLOCRETRY) Printf(" ALLOCRETRY,");
	if (unitptr->vdu_Flags & VDF_ERRORKILL) Printf(" ERRORKILL,");
	if (unitptr->vdu_Flags & VDF_AUTOMOUNT) Printf(" AUTOMOUNT,");
	if (unitptr->vdu_Flags & VDF_BOOTABLE) Printf(" BOOTABLE,");
	if (unitptr->vdu_Flags & VDF_NOCLEAN) Printf(" NOCLEAN,");
	if (unitptr->vdu_Flags & VDF_VOLATILE) Printf(" VOLATILE,");
	Printf("\b \n");
	Printf("Allocation flags:  PUBLIC,");
	if (unitptr->vdu_AllocFlags & MEMF_CHIP) Printf(" CHIP,");
	if (unitptr->vdu_AllocFlags & MEMF_FAST) Printf(" FAST,");
	if (unitptr->vdu_AllocFlags & MEMF_LOCAL) Printf(" LOCAL,");
	if (unitptr->vdu_AllocFlags & MEMF_24BITDMA) Printf(" 24BITDMA,");
	if (unitptr->vdu_AllocFlags & MEMF_KICK) Printf(" KICK,");
	Printf("\b \n");
      }
      error = VDiskBase->vd_RecErr & 0xff;
      if (error == VDE_NoRoot || error == VDE_BadRootSum || error == VDE_BadRootVer)
      { Printf("VDisk General Recovery error %ld: %s\n", error, VD_RecErrTxt(error));
	rc = 5;
      }
      else if (error = VDiskBase->vd_Root->vdr_RecErrs[unit])
      { Printf("VDisk Unit %ld Recovery error %ld : %s\n", unit, error, VD_RecErrTxt(error));
	rc = 5;
      }
      else Printf("No recovery error for VDisk Unit %ld\n", unit);
    }
    else Printf("VDisk unit %ld is not active\n", unit);
    CloseDevice(&vdio);
  }     
  else
  { Printf("Couldn't open vdisk.device : Error %ld\n", error);
    rc = 20;
  }
  clearall();
  return(rc);
}

STRPTR VD_RecErrTxt(ULONG vde_code)
{
  register STRPTR texte;

  switch(vde_code)
  { case VDE_Deleted:
      texte = "Deleted Unit";
      break;
    case VDE_NoRoot:
      texte = "Root Structure not found";
      break;
    case VDE_BadRootSum:
      texte = "Bad Root Structure Checksum";
      break;
    case VDE_BadSecSum:
      texte = "Bad Sector Checksum";
      break;
    case VDE_NoVTrack:
      texte = "Track not found";
      break;
    case VDE_AllocError:
      texte = "Reallocation Failure";
      break;
    case VDE_NoUnit:
      texte = "Unit Structure not found";
      break;
    case VDE_BadUnitSum:
      texte = "Bad Unit Structure Checksum";
      break;
    case VDE_BadRootVer:
      texte = "Root Structure Version mismatch";
      break;
    default:
      texte = "Unknown Error";
      break;
  }
  return(texte);
}

static void clearall(void)
{
  if (myrda) FreeArgs(myrda);
  if (DOSBase) CloseLibrary((struct Library *)DOSBase);
  if (wbmsg)
  { Forbid();
    ReplyMsg((struct Message *)wbmsg);
  }
}

#ifdef __SASC
void __regargs __chkabort(void)
{
}
#endif
