/*
**	$RCSfile: DevInfo.c,v $
**	$Filename: DevInfo.c $
**	$Revision: 1.2 $
**	$Date: 2002/01/05 18:17:13 $
**
**	DevInfo source file (version 1.2 beta) 
**
**	(C) Copyright 1993-2001 by Etienne Vogt
*/

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/alerts.h>
#include <dos/dos.h>
#include <dos/rdargs.h>
#include <workbench/startup.h>
#include <stdlib.h>
#include <string.h>

#define __USE_SYSBASE
#include <proto/exec.h>
#include <proto/dos.h>

#include "errorlog.h"

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

/* Global variables */

struct ExecBase *SysBase;
static struct WBStartup *wbmsg;
static struct RDArgs *myrda;

static STRPTR version = "$VER: DevInfo 1.2 beta (29.12.2001)";
static STRPTR template = "DEVICE,FULL/S";

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


ULONG __saveds main(void)
{
  struct Process *myproc;
  LONG opts[OPTMAX];

  struct HellGate *hgate;
  struct DoomNode *dnode, *copnodes, *DNp;
  int i;
  ULONG opcount, logcount, errorcount, abortcount;
  APTR pbegIO, pabIO, dcb;
  ULONG rc = 0;
  BOOL found = FALSE;

  SysBase = *(struct ExecBase **)4;
  DOSBase = 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);
  }
  memset((char *)opts, 0, sizeof(opts));
  if ((myrda = ReadArgs(template, opts, NULL)) == NULL)
  { PrintFault(IoErr(),NULL);
    clearall();
    return(20);
  }

  if (opts[OPT_DEVICE])
  {
    UBYTE *colon;

    if (colon = (UBYTE *)strchr((const char *)opts[OPT_DEVICE],':')) *colon = (UBYTE)0;
  }

  Forbid();
  if (hgate = (struct HellGate *)FindSemaphore("ErrorLog.HellGate"))
  { ObtainSemaphoreShared(&hgate->hg_SigSem);
    Permit();
    logcount = hgate->hg_LogCount;
    errorcount = hgate->hg_ErrorCount;
    opcount = hgate->hg_OpCount;
    abortcount = hgate->hg_AbortCount;
    pbegIO = (APTR)hgate->hg_PatchBeginIO;
    pabIO = (APTR)hgate->hg_PatchAbortIO;
    dcb = (APTR)hgate->hg_DummyCopyBuff;
    if (copnodes = (struct DoomNode *)AllocVec(logcount * sizeof(struct DoomNode), MEMF_PUBLIC))
    { for (i = 0, DNp = copnodes, dnode = (struct DoomNode *)hgate->hg_DoomList.lh_Head;
	   i < logcount;
	   dnode = (struct DoomNode *)dnode->dn_Link.ln_Succ, i++, DNp++)
      { CopyMem(dnode, DNp, sizeof(struct DoomNode));
      }
      ReleaseSemaphore(&hgate->hg_SigSem);
      PutStr("\n");
      if (opts[OPT_FULL])
      { Printf("Currently Logged Devices/units : %ld\n",logcount);
	Printf("Total Operations completed     : %ld\n",opcount);
	Printf("Total Operations aborted       : %ld\n",abortcount);
	Printf("Total Errors on Logged units   : %ld\n",errorcount);
	Printf("Patched BeginIO() code         : %08lx\n",pbegIO);
	Printf("Patched AbortIO() code         : %08lx\n",pabIO);
	Printf("Dummy CopyBuff() routine       : %08lx\n",dcb);
	Printf("\n");
      }
      for (i = 0, DNp = copnodes; i < logcount; i++, DNp++)
	if (!opts[OPT_DEVICE] || !strnicmp((char *)opts[OPT_DEVICE], DNp->dn_Link.ln_Name, DNAME_SIZE))
	{ found = TRUE;
	  Printf("%.8s : Device %.24s, Unit %ld, ", DNp->dn_Link.ln_Name, &DNp->dn_DeviceName, DNp->dn_UnitNum);
	  if (DNp->dn_Flags & DNF_ENABLED) PutStr("enabled, ");
	  else PutStr("disabled, ");
	  if (DNp->dn_Flags & DNF_LOGERRORS) PutStr("error logging on\n");
	  else PutStr("error logging off\n");
	  Printf("Operations completed    : %lu\n",DNp->dn_OpCount);
	  Printf("Operations pending      : %lu\n",DNp->dn_ActiveCount);
	  Printf("Error count             : %lu\n",(LONG)DNp->dn_ErrorCount);
	  if (opts[OPT_FULL])
	  { Printf("DoomList priority       : %ld\n",(LONG)DNp->dn_Link.ln_Pri);
	    Printf("Device base address     : %08lx\n",DNp->dn_IOReq.ios2_Req.io_Device);
	    Printf("Unit base address       : %08lx\n",DNp->dn_IOReq.ios2_Req.io_Unit);
	    Printf("Device Type             : %lu\n",(ULONG)DNp->dn_DevType);
	    Printf("Device SubType          : %lu\n",(ULONG)DNp->dn_DevSubType);
	    Printf("IORequest size (bytes)  : %lu\n",(ULONG)DNp->dn_IOSize);
	    Printf("Original BeginIO() code : %08lx\n",DNp->dn_OrigBeginIO);
	    Printf("Original AbortIO() code : %08lx\n",DNp->dn_OrigAbortIO);
	  }
	  PutStr("\n");
	} 
      FreeVec(copnodes);
      if (opts[OPT_DEVICE] && !found) Printf("Error : Couldn't find DoomNode %s\n",(STRPTR)opts[OPT_DEVICE]);
    }
    else 
    { ReleaseSemaphore(&hgate->hg_SigSem);
      Printf("Error : Not enough memory to scan DoomList\n"); 
      rc = 20;
    }
  }
  else
  { Permit();
    Printf("Error : The ErrorLog.daemon is not running.\n");
    rc = 10;
  }
  clearall();
  return rc;
}

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
