text: /*++
  
  Copyright (c) 1989  Microsoft Corporation
  
  Module Name:
  
      RxLog.c
  
  Abstract:
  
      This module implements the logging system used by the Rx file system.
  
  Author:
  
      JoeLinn     [JoeLinn]    1-Dec-94
  
  Revision History:
  
      Balan Sethu Raman [SethuR] 24-April-95
           Revised to conform to new log record layout.
  
  --*/
  
  #include "precomp.h"
  #pragma hdrstop
  #include "stdarg.h"
  #include "stdio.h"
  #include "stdlib.h"
  #include "string.h"
  #include "prefix.h"
  
  #ifdef  ALLOC_PRAGMA
  #pragma alloc_text(PAGE, RxUninitializeLog)
  #pragma alloc_text(PAGE, RxInitializeLog)
  #pragma alloc_text(PAGE, RxPrintLog)
  #pragma alloc_text(PAGE, RxpTrackDereference)
  #endif
  
  #if !DBG
  #undef RDBSSTRACE
  #endif
  
  //
  //  The debug trace level
  //
  
  #define Dbg                              (0)
  
  #define RDBSSHUGELOG
  
  #if DBG
  #define RX_LOG_BUFFER_SIZE 5000
  #else
  #if RDBSSLOG
  #define RX_LOG_BUFFER_SIZE 500
  #else
  #define RX_LOG_BUFFER_SIZE 0
  #endif
  #endif
  
  #define MAX_RX_LOG_BUFFER_ALLOC   (256*1024)
  #define RX_LOG_MAX_MDLLIST_LENGTH 100
  
  RX_LOG s_RxLog = {0,RX_LOG_UNINITIALIZED,NULL,NULL,NULL,0,0,0,0};
  
  PUCHAR RxContxOperationNames[] = {
        RDBSSLOG_ASYNC_NAME_PREFIX "CREATE",    //#define IRP_MJ_CREATE                   0x00
        RDBSSLOG_ASYNC_NAME_PREFIX "CR_NMPIPE", //#define IRP_MJ_CREATE_NAMED_PIPE        0x01
        RDBSSLOG_ASYNC_NAME_PREFIX "CLOSE",     //#define IRP_MJ_CLOSE                    0x02
        RDBSSLOG_ASYNC_NAME_PREFIX "READ",      //#define IRP_MJ_READ                     0x03
        RDBSSLOG_ASYNC_NAME_PREFIX "WRITE",     //#define IRP_MJ_WRITE                    0x04
        RDBSSLOG_ASYNC_NAME_PREFIX "QUERYINFO", //#define IRP_MJ_QUERY_INFORMATION        0x05
        RDBSSLOG_ASYNC_NAME_PREFIX "SETINFO",   //#define IRP_MJ_SET_INFORMATION          0x06
        RDBSSLOG_ASYNC_NAME_PREFIX "QUERYEA",   //#define IRP_MJ_QUERY_EA                 0x07
        RDBSSLOG_ASYNC_NAME_PREFIX "SETEA",     //#define IRP_MJ_SET_EA                   0x08
        RDBSSLOG_ASYNC_NAME_PREFIX "FLUSH",     //#define IRP_MJ_FLUSH_BUFFERS            0x09
        RDBSSLOG_ASYNC_NAME_PREFIX "QUERYVOL",  //#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a
        RDBSSLOG_ASYNC_NAME_PREFIX "SETVOL",    //#define IRP_MJ_SET_VOLUME_INFORMATION   0x0b
        RDBSSLOG_ASYNC_NAME_PREFIX "DIRCTRL",   //#define IRP_MJ_DIRECTORY_CONTROL        0x0c
        RDBSSLOG_ASYNC_NAME_PREFIX "FSCTL",     //#define IRP_MJ_FILE_SYSTEM_CONTROL      0x0d
        RDBSSLOG_ASYNC_NAME_PREFIX "IOCTL",     //#define IRP_MJ_DEVICE_CONTROL           0x0e
        RDBSSLOG_ASYNC_NAME_PREFIX "xIOCTL",    //#define IRP_MJ_INTERNAL_DEVICE_CONTROL  0x0f
        RDBSSLOG_ASYNC_NAME_PREFIX "SHUTDWN",   //#define IRP_MJ_SHUTDOWN                 0x10
        RDBSSLOG_ASYNC_NAME_PREFIX "LOCKCTRL",  //#define IRP_MJ_LOCK_CONTROL             0x11
        RDBSSLOG_ASYNC_NAME_PREFIX "CLEANUP",   //#define IRP_MJ_CLEANUP                  0x12
        RDBSSLOG_ASYNC_NAME_PREFIX "CR_MLSLOT", //#define IRP_MJ_CREATE_MAILSLOT          0x13
        RDBSSLOG_ASYNC_NAME_PREFIX "QUERYSCRTY",//#define IRP_MJ_QUERY_SECURITY           0x14
        RDBSSLOG_ASYNC_NAME_PREFIX "SETSCRTY",  //#define IRP_MJ_SET_SECURITY             0x15
        RDBSSLOG_ASYNC_NAME_PREFIX "QUERYPWR",  //#define IRP_MJ_QUERY_POWER              0x16
        RDBSSLOG_ASYNC_NAME_PREFIX "NOTDEFND",  //#define IRP_MJ_NOT_DEFINED              0x17
        RDBSSLOG_ASYNC_NAME_PREFIX "DVCHANGE",  //#define IRP_MJ_DEVICE_CHANGE            0x18
        RDBSSLOG_ASYNC_NAME_PREFIX "QRYQUOTA",  //#define IRP_MJ_QUERY_QUOTA              0x19
        RDBSSLOG_ASYNC_NAME_PREFIX "SETQUOTA",  //#define IRP_MJ_SET_QUOTA                0x1a
        RDBSSLOG_ASYNC_NAME_PREFIX "PNPPOWER",  //#define IRP_MJ_PNP_POWER                0x1b
        RDBSSLOG_ASYNC_NAME_PREFIX "********",  //internal init            0x1c
          "XX"
           //#define IRP_MJ_MAXIMUM_FUNCTION         0x1b
           };
  
  PRX_LOG_ENTRY_HEADER
  RxGetNextLogEntry(void)
  {
      PRX_LOG_ENTRY_HEADER pEntry;
      // you have to hold the spinlock for this....
  
      pEntry = s_RxLog.CurrentEntry + 1;
      if (pEntry == s_RxLog.EntryLimit){
          s_RxLog.NumberOfLogWraps++;
          pEntry = s_RxLog.BaseEntry;
      }
  
      s_RxLog.CurrentEntry = pEntry;
      return pEntry;
  }
  
  VOID
  RxUninitializeLog ()
  {
      PRX_LOG_ENTRY_HEADER EntryLimit = s_RxLog.EntryLimit;
      PMDL *MdlList = (PMDL *)(EntryLimit+1);
  
      PAGED_CODE();
  
      //NOTE: none of this is happening under spinlock!
      //DbgPrint("UninitLog: mdllist=%08lx,*mdllist=%08lx\n",MdlList,*MdlList);
      //DbgBreakPoint();
  
      if ((s_RxLog.State == RX_LOG_UNINITIALIZED) ||
          (s_RxLog.State == RX_LOG_ERROR)) {
          return;
      }
  
      s_RxLog.State = RX_LOG_UNINITIALIZED;
  
      for (;;) {
          PMDL Mdl = *MdlList;
          PUCHAR Buffer;
          if (Mdl == NULL) break;
          Buffer = MmGetMdlVirtualAddress(Mdl);
          //DbgPrint("UninitLog: buffer=%08lx,mdl=%08lx\n",Buffer,Mdl);
          MmUnlockPages(Mdl);
          IoFreeMdl(Mdl);
          RxFreePool(Buffer);
          MdlList++;
      }
  
      RxFreePool(s_RxLog.BaseEntry);
      return;
  };
  
  
  
  NTSTATUS
  RxInitializeLog ()
  {
      ULONG NumEntries = RX_LOG_BUFFER_SIZE;
      ULONG NumEntriesLeft;
      ULONG LogSize = (NumEntries+1)*sizeof(RX_LOG_ENTRY_HEADER);
      PRX_LOG_ENTRY_HEADER BaseEntry=NULL,EntryLimit=NULL;
      PRX_LOG_ENTRY_HEADER p;
      PUCHAR NextBuffer;
      PMDL *MdlList;
      ULONG MdlListLength = RX_LOG_MAX_MDLLIST_LENGTH*sizeof(PMDL);
      ULONG MdlsLeft = RX_LOG_MAX_MDLLIST_LENGTH;
      ULONG SpaceLeft;
  
      PAGED_CODE();
  
      if (s_RxLog.State != RX_LOG_UNINITIALIZED) {
          return (STATUS_SUCCESS);
      }
      //only do this stuff once
      KeInitializeSpinLock( &s_RxLog.SpinLock );
      s_RxLog.LogBufferSizeInEntries = NumEntries;
  
      //first allocate the marginal index array
      BaseEntry = RxAllocatePoolWithTag(NonPagedPool,LogSize+MdlListLength,'xr');
      if (BaseEntry==NULL) {
          s_RxLog.State = RX_LOG_ERROR;
          DbgPrint("Couldn't initialize log1");
          return (STATUS_INSUFFICIENT_RESOURCES);
      }
      s_RxLog.BaseEntry = BaseEntry;
      EntryLimit = s_RxLog.EntryLimit = BaseEntry+NumEntries;
      MdlList = (PMDL *)(EntryLimit+1);
      *MdlList = 0;
      //DbgPrint("InitLog: mdllist=%08lx,*mdllist=%08lx\n",MdlList,*MdlList);
  
      //now allocate wspace for the actual buffers...since we may be asking for a lot
      // we allocate from pages pool and lock down.
  
      SpaceLeft = 0;
      for (   p=BaseEntry,NumEntriesLeft=NumEntries;
              NumEntriesLeft>0;
              p++,NumEntriesLeft--  ) {
  
          if (SpaceLeft<sizeof(RX_LOG_ENTRY_HEADER)) {
              PMDL Mdl = NULL;
              PUCHAR Buffer=NULL;
              NTSTATUS Status;
              ULONG AllocLength = min(MAX_RX_LOG_BUFFER_ALLOC,
                                      NumEntriesLeft*MAX_RX_LOG_ENTRY_SIZE);
              for (;;) {
                  Buffer = RxAllocatePoolWithTag(PagedPool,AllocLength,'xr');
                  if (Buffer) break;
                  DbgPrint("InitLog: failed alloc at %08lx",AllocLength);
                  if (AllocLength<PAGE_SIZE) break;
                  AllocLength >>= 3;
                  NumEntriesLeft = AllocLength / MAX_RX_LOG_ENTRY_SIZE;
              }
              if (Buffer==NULL) {
                  s_RxLog.State = RX_LOG_ERROR;
                  DbgPrint("Couldn't initialize log2");
                  RxFreePool(BaseEntry);
                  return (STATUS_INSUFFICIENT_RESOURCES);
              }
              if (MdlsLeft==0) {
                  s_RxLog.State = RX_LOG_ERROR;
                  DbgPrint("Couldn't initialize log3");
                  RxFreePool(Buffer);
                  RxFreePool(BaseEntry);
                  return (STATUS_INSUFFICIENT_RESOURCES);
              }
              Mdl = RxAllocateMdl(Buffer,AllocLength);
              if (Mdl==NULL) {
                  s_RxLog.State = RX_LOG_ERROR;
                  DbgPrint("Couldn't initialize log4");
                  RxFreePool(Buffer);
                  RxFreePool(BaseEntry);
                  return (STATUS_INSUFFICIENT_RESOURCES);
              }
  
              RxProbeAndLockPages(Mdl,KernelMode,IoModifyAccess,Status);
              if (Status!=(STATUS_SUCCESS)) {
                  s_RxLog.State = RX_LOG_ERROR;
                  DbgPrint("Couldn't initialize log5");
                  RxFreePool(Mdl);
                  RxFreePool(Buffer);
                  RxFreePool(BaseEntry);
                  return Status;
              }
              //DbgPrint("InitLog: newbuf=%08lx,mdl=%08lx,alloc=%08lx\n",Buffer,Mdl,AllocLength);
              MdlsLeft--;
              *MdlList = Mdl;
              MdlList++;
              *MdlList = NULL;
  
              NextBuffer = MmGetSystemAddressForMdlSafe(Mdl, LowPagePriority);
  
              if (NextBuffer == NULL) {
                  s_RxLog.State = RX_LOG_ERROR;
                  DbgPrint("Couldn't initialize log5");
                  MmUnlockPages(Mdl);
                  RxFreePool(Mdl);
                  RxFreePool(Buffer);
                  RxFreePool(BaseEntry);
                  return STATUS_INSUFFICIENT_RESOURCES;
              }
  
              SpaceLeft = AllocLength;
          }
  
          p->Buffer = NextBuffer;
          *((PULONG)NextBuffer) = '###';
          NextBuffer += MAX_RX_LOG_ENTRY_SIZE;
          SpaceLeft -= MAX_RX_LOG_ENTRY_SIZE;
      }
  
      //DbgPrint("Init Log: numeleft,nummleft=%d,%d\n",NumEntriesLeft,MdlsLeft);
      p->Buffer = (PUCHAR)IntToPtr(0xf00df00d);
      s_RxLog.State = RX_LOG_ENABLED;
      s_RxLog.CurrentEntry = EntryLimit-1;
  
      //DbgPrint("Init Log: exit\n");
      return((STATUS_SUCCESS));
  
  }
  
  VOID
  _RxPauseLog ()
  {
      KIRQL oldIrql;
  
      KeAcquireSpinLock( &s_RxLog.SpinLock, &oldIrql );
  
      if (s_RxLog.State == RX_LOG_ENABLED) {
         s_RxLog.State = RX_LOG_DISABLED;
      }
  
      KeReleaseSpinLock( &s_RxLog.SpinLock, oldIrql );
  }
  
  VOID
  _RxResumeLog()
  {
      KIRQL oldIrql;
  
      KeAcquireSpinLock( &s_RxLog.SpinLock, &oldIrql );
  
      if (s_RxLog.State == RX_LOG_DISABLED) {
         s_RxLog.State = RX_LOG_ENABLED;
      }
  
      KeReleaseSpinLock( &s_RxLog.SpinLock, oldIrql );
  }
  
  VOID
  RxPrintLog (
      IN ULONG EntriesToPrint OPTIONAL
      )
  {
      //KIRQL oldIrql;
      PRX_LOG_ENTRY_HEADER LogEntry,EntryLimit;
      ULONG i=0;
  
      PAGED_CODE();
  
      RxPauseLog();
  
      if (EntriesToPrint==0) {
          EntriesToPrint =  RX_LOG_BUFFER_SIZE;
      }
      DbgPrint("\n\n\nLog Print: Entries = %lu \n", EntriesToPrint);
  
      LogEntry = s_RxLog.CurrentEntry-1;
      EntryLimit = s_RxLog.EntryLimit;
      for (;EntriesToPrint>0;EntriesToPrint--) {
          LogEntry++;
          if (LogEntry>=EntryLimit) {
              LogEntry = s_RxLog.BaseEntry;
          }
          DbgPrint("%0ld: %s\n",i++,LogEntry->Buffer);
      }
  
      RxResumeLog();
  }
  
  
  VOID
  _RxLog(char *Format, ...)
  {
     va_list arglist;
     KIRQL   oldIrql;
     CLONG   LogEntryLength = 0;
     BOOLEAN fLogNewEntry = TRUE;
     PRX_LOG_ENTRY_HEADER LogEntry;
     CHAR    EntryString[MAX_RX_LOG_ENTRY_SIZE];
     PCHAR   pEntryString;
     CHAR    FormatChar;
     CHAR    FieldString[MAX_RX_LOG_ENTRY_SIZE];
     ULONG   FieldLength;
     char *OriginalFormat = Format;
     ULONG BinaryArgs = 0;
     ULONG BinaryStringMask = 1;  //the first arg is always a string!!!!
  
     //DbgPrint("RxLog: entry\n");
     if (s_RxLog.State != RX_LOG_ENABLED) {
        return;
     }
  
     pEntryString = EntryString;
  
     va_start(arglist, Format);
     //DbgBreakPoint();
  
     for (;;) {
        // Copy the format string
        while ((LogEntryLength < MAX_RX_LOG_ENTRY_SIZE) &&
               ((FormatChar = *Format++) != '\0') &&
               (FormatChar != '%')) {
           if (FormatChar != '\n'){
               pEntryString[LogEntryLength++] = FormatChar;
           }
        }
  
        if ((LogEntryLength < MAX_RX_LOG_ENTRY_SIZE) &&
            (FormatChar == '%')) {
           if ( (*Format == 'l') || (*Format == 'w') ) {
              Format++;
           }
           switch (*Format++) {
           case 'N': //binary placement -- don't try to make it foolproof
              {
                  BinaryArgs++;
                  *((PULONG)(&EntryString[sizeof(ULONG)])+BinaryArgs) = (ULONG)va_arg(arglist,ULONG);
              }
              break;
           case 'S': //binary placement -- don't try to make it foolproof
              {
                  BinaryArgs++;
                  BinaryStringMask |= 1<<(BinaryArgs-1);
                  //DbgPrint("BSM %08lx\n",BinaryStringMask);
                  *((PULONG)(&EntryString[sizeof(ULONG)])+BinaryArgs) = (ULONG)va_arg(arglist,ULONG);
              }
              break;
           case 'd':
              {
                // _itoa((LONG)va_arg(arglist,LONG),FieldString,10);
                // FieldLength = strlen(FieldString);// + 1;
                // if ((LogEntryLength + FieldLength) < MAX_RX_LOG_ENTRY_SIZE) {
                //    strcpy(&pEntryString[LogEntryLength],FieldString);
                //    LogEntryLength += FieldLength;
                //    //pEntryString[LogEntryLength - 1] = ' ';
                // }
                  LONG l = (LONG)va_arg(arglist,LONG);
                  if ((LogEntryLength + 5) < MAX_RX_LOG_ENTRY_SIZE) {
                      pEntryString[LogEntryLength++] = 0x5;
                      pEntryString[LogEntryLength++] = (UCHAR)(0xff&(l>>0));
                      pEntryString[LogEntryLength++] = (UCHAR)(0xff&(l>>8));
                      pEntryString[LogEntryLength++] = (UCHAR)(0xff&(l>>16));
                      pEntryString[LogEntryLength++] = (UCHAR)(0xff&(l>>24));
                  }
              }
              break;
           case 'c':
              pEntryString[LogEntryLength++] = (CHAR)va_arg(arglist,char);
              break;
           case 'x':
              {
                // _itoa((LONG)va_arg(arglist,LONG),FieldString,16);
                // FieldLength = strlen(FieldString);// + 1;
                // if ((LogEntryLength + FieldLength) < MAX_RX_LOG_ENTRY_SIZE) {
                //    strcpy(&pEntryString[LogEntryLength],FieldString);
                //    LogEntryLength += FieldLength;
                //    //pEntryString[LogEntryLength - 1] = ' ';
                // }
                  LONG l = (LONG)va_arg(arglist,LONG);
                  if ((LogEntryLength + 5) < MAX_RX_LOG_ENTRY_SIZE) {
                      pEntryString[LogEntryLength++] = 0x4;
                      pEntryString[LogEntryLength++] = (UCHAR)(0xff&(l>>0));
                      pEntryString[LogEntryLength++] = (UCHAR)(0xff&(l>>8));
                      pEntryString[LogEntryLength++] = (UCHAR)(0xff&(l>>16));
                      pEntryString[LogEntryLength++] = (UCHAR)(0xff&(l>>24));
                  }
              }
              break;
           case 's':
              {
                 PCHAR pString = &pEntryString[LogEntryLength];
                 PCHAR pArg    = (PCHAR)va_arg(arglist, PCHAR);
  
                 ASSERT(pArg!=NULL);
                 FieldLength = strlen(pArg);// + 1;
                 if ((LogEntryLength + FieldLength) < MAX_RX_LOG_ENTRY_SIZE) {
                    strcpy(pString,pArg);
                    LogEntryLength += FieldLength;
                    //pEntryString[LogEntryLength - 1] = ' ';
                 }
              }
              break;
           case 'Z':
              {
                 PCHAR pString = &pEntryString[LogEntryLength];
                 PUNICODE_STRING pArg    = (PUNICODE_STRING)va_arg(arglist, PUNICODE_STRING);
                 PWCHAR Buffer;
                 ULONG Length;
  
                 //this really only works for ascii strings in unicode......
                 ASSERT(pArg!=NULL);
                 Buffer = pArg->Buffer;
                 // Make sure the length is WCHAR aligned
                 Length = (pArg->Length & ~(sizeof(WCHAR)-1));
                 //DbgPrint("yaya=%08lx,%08lx,%08lx\n",pArg,Buffer,Length);
                 for (;Length>0;Length-=sizeof(WCHAR)) {
                     if (LogEntryLength < MAX_RX_LOG_ENTRY_SIZE) {
                         pEntryString[LogEntryLength++] = (UCHAR)(*Buffer++);
                     } else {
                         break;
                     }
                 }
                 //DbgBreakPoint();
              }
              break;
           default:
              fLogNewEntry = FALSE;
              break;
           }
        } else {
           break;
        }
     }
  
     va_end(arglist);
  
     if (BinaryArgs) {
         EntryString[0] = '#';
         EntryString[1] = '>';
         EntryString[2] = '0'+(UCHAR)BinaryArgs;
         EntryString[3] = 0;
         *((PULONG)(&EntryString[sizeof(ULONG)])) = BinaryStringMask;
         LogEntryLength = MAX_RX_LOG_ENTRY_SIZE;
     }
  
     KeAcquireSpinLock( &s_RxLog.SpinLock, &oldIrql );
  
     if (fLogNewEntry) {
        s_RxLog.NumberOfLogWriteAttempts++;
        LogEntry = RxGetNextLogEntry();
     } else {
        s_RxLog.NumberOfEntriesIgnored++;
        DbgPrint("RxLog: Entry exceeds max size, not recorded <%s>\n",OriginalFormat);
        if (s_RxLog.NumberOfEntriesIgnored==1) {
            //DbgBreakPoint();
        }
     }
  
     KeReleaseSpinLock( &s_RxLog.SpinLock, oldIrql );
  
     if (fLogNewEntry) {
          BOOLEAN OutOfBounds = ((LogEntry<s_RxLog.BaseEntry) || (LogEntry>=s_RxLog.EntryLimit));
          if (OutOfBounds) {
            DbgPrint("RxLog: wrap logic has fail.....log disabled\n");
            s_RxLog.State = RX_LOG_DISABLED;
          } else {
              if (LogEntryLength >= MAX_RX_LOG_ENTRY_SIZE) {
                  LogEntryLength = MAX_RX_LOG_ENTRY_SIZE;
                  if (BinaryArgs == 0) {
                      pEntryString[MAX_RX_LOG_ENTRY_SIZE-1] = 0;
                  }
              } else {
                  pEntryString[LogEntryLength++] = 0;
              }
              RtlCopyMemory(LogEntry->Buffer,pEntryString,LogEntryLength);
          }
     }
  }
  
  #define RxToUpper(CH) ((CH)&~('A'^'a'))
  #define RxIsLetter(CH) ((RxToUpper(CH)>='A') && (RxToUpper(CH)<='Z'))
  #define RxIsDigit(CH) (((CH)>='0')&&((CH)<='9'))
  
  VOID
  RxDebugControlCommand (
      IN char *ControlString
      )
  /*
      This routine manipulates the print and log levels and the breakpoint masks. the format is
  
            AAAAA+AAAAA+AAAAA+AAAAA.....
  
       where each AAAAA == <+-!>*<Letter>*<digit>*.
  
       <letter>* designates a control name.....only enuff to disambiguate is needed.
  
       any + turns on  tracing globally
       any % turns on  tracing globally RIGHT NOW!
       any - turns off tracing globally
  
       for 0 !s, it means:  for the control <letter>*, set the printlevel to <digit>*
       for 1 !s, it means:  for the control <letter>* set breakmask bit <digit>*. 0 means all bits
       for 2 !s, it means:  for the control <letter>* clear breakmask bit <digit>*. 0 means all bits
           THIS STUFF (I.E. THE ! STUFF)  IS ACTUALLY IMPLEMENTED IN RXTRACE.C
  
       @ means  printlog
       @@ means   pauselog
       @@@ means resumelog
       @@@@ means initialize
       @@@@@ means setup to debug by turning off printing
       more than @@@@@ means  banner
  
  
       E.G. cle0+clo0+cre1000+!devf3 sets disables printing for cleanup and close, sets the printlevel
            for create to 1000, and enables the third bit of the breakmask for devfcb.
  
       the letter string is upcased automatically.
  
       There is usually one control for each file but some controls control stuff from multiple
       files (like dispatch)
  */
  {
      char namebuf[16], numbuf[16], *p, *q, *c;
      //long i;
      long level,pointcount,atsigncount;
      //DEBUG_TRACE_CONTROLS control;
  
      //ASSERTMSG("Here in debug command parser!\n",FALSE);
      RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("RxDebugTraceControl %s!!\n", ControlString));
  
      if (!ControlString)
      {
          return;
      }
  
      for (c = ControlString;;) {
          if (*c == 0) break;
          p=namebuf;q=numbuf; atsigncount=pointcount = 0;
          for (;(*c!=0)&&!RxIsLetter(*c)&&!RxIsDigit(*c); c++){     //skip to a letter or digit
              if (*c == '!') {
                  pointcount++;
              }
              if (*c == '@') {
                  atsigncount++;
              }
  #if RDBSSTRACE
              if (*c == '+') {
                  RxNextGlobalTraceSuppress = FALSE;
              }
              if (*c == '%') {
                  RxGlobalTraceSuppress = FALSE;
              }
              if (*c == '-') {
                  RxNextGlobalTraceSuppress = TRUE;
              }
  #endif //RDBSSTRACE
          }
          for (p=namebuf;(*c!=0)&&RxIsLetter(*c); *p++=RxToUpper(*c++) ) ;    //copy letters
          for (level=0,q=numbuf;(*c!=0)&&RxIsDigit(*c); *q++=*c++){           //copy digits
              level = 10*level+((*c)-'0');
          }
          *p = *q = (char)0;
          {if (atsigncount>0) {
              if (atsigncount==1) {
                  RxPrintLog(level);
              } else if (atsigncount == 2) {
                  RxPauseLog();
              } else if (atsigncount == 3) {
                  RxResumeLog();
              } else if (atsigncount == 4) {
                  RxInitializeLog();
              } else if (atsigncount == 5){
  #if RDBSSTRACE
                  RxDebugTraceZeroAllPrintLevels();
                  RxDbgTraceFindControlPoint((DEBUG_TRACE_UNWIND))->PrintLevel = 10000;
                  RxDbgTraceFindControlPoint((DEBUG_TRACE_READ))->PrintLevel = 10000;
                  RxDbgTraceFindControlPoint((DEBUG_TRACE_RXCONTX))->PrintLevel = 1000;
                  RxDbgTraceFindControlPoint((DEBUG_TRACE_DISPATCH))->PrintLevel = 1000;
                  RxDbgTraceFindControlPoint((DEBUG_TRACE_CREATE))->PrintLevel = 10000;
                  RxDbgTraceFindControlPoint((DEBUG_TRACE_CLEANUP))->PrintLevel = 10000;
                  RxDbgTraceFindControlPoint((DEBUG_TRACE_CLOSE))->PrintLevel = 10000;
  #endif
              } else {
  #if RDBSSTRACE
                  RxDbgTrace(0, (DEBUG_TRACE_ALWAYS), ("\n\n\n\n\n %s %s\n\n\n\n\n", namebuf, numbuf));
  #endif
              }
              continue;
          }}
  #if RDBSSTRACE
          if (((*namebuf)==0||(*numbuf)==0)) {
              continue;
          }
          RxDebugTraceDebugCommand(namebuf,level,pointcount);
  #endif
      }
      return;
  }
  
  #ifdef DBG
  VOID
  RxpTrackReference(
        ULONG   TraceType,
        PCHAR   FileName,
        ULONG   Line,
        PVOID   pInstance)
  {
     if (REF_TRACING_ON(TraceType)) {
        ULONG RefCount;
        PCHAR pTypeName,pLogTypeName;
  
        switch (TraceType) {
        case RDBSS_REF_TRACK_SRVCALL :
           pTypeName    = "SrvCall";
           pLogTypeName = "SC";
           RefCount     = ((PSRV_CALL)pInstance)->NodeReferenceCount;
           RxWmiLog(SRVCALL,RxRefSrvcall,LOGPTR(pInstance)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
           break;
        case RDBSS_REF_TRACK_NETROOT :
           pTypeName = "NetRoot";
           pLogTypeName = "NR";
           RefCount     = ((PNET_ROOT)pInstance)->NodeReferenceCount;
           RxWmiLog(NETROOT,RxRefNetRoot,LOGPTR(pInstance)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
           break;
        case RDBSS_REF_TRACK_VNETROOT:
           pTypeName = "VNetRoot";
           pLogTypeName = "VN";
           RefCount     = ((PV_NET_ROOT)pInstance)->NodeReferenceCount;
           RxWmiLog(VNETROOT,RxRefVNetRoot,LOGPTR(pInstance)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
           break;
        case RDBSS_REF_TRACK_NETFOBX :
           pTypeName = "NetFobx";
           pLogTypeName = "FO";
           RefCount     = ((PFOBX)pInstance)->NodeReferenceCount;
           RxWmiLog(FOBX,RxRefFobx,LOGPTR(pInstance)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
           break;
        case RDBSS_REF_TRACK_NETFCB  :
           pTypeName = "NetFcb";
           pLogTypeName = "FC";
           RefCount     = ((PFCB)pInstance)->NodeReferenceCount;
           RxWmiLog(FCB,RxRefFcb,LOGPTR(pInstance)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
           break;
        case RDBSS_REF_TRACK_SRVOPEN :
           pTypeName = "SrvOpen";
           pLogTypeName = "SO";
           RefCount     = ((PSRV_OPEN)pInstance)->NodeReferenceCount;
           RxWmiLog(SRVOPEN,RxRefSrvOpen,LOGPTR(pInstance)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
           break;
        default:
           DbgPrint("Invalid Node Type for referencing\n");
           //DbgBreakPoint();
           return;
        }
  
        if (RdbssReferenceTracingValue & RX_LOG_REF_TRACKING) {
           RxLog(("Ref.%s %lx %ld %lx %ld->%ld",pLogTypeName,pInstance,Line,FileName,RefCount,RefCount+1));
        }
  
        if (RdbssReferenceTracingValue & RX_PRINT_REF_TRACKING) {
           DbgPrint("Reference %s  %lx %ld %s\n",pTypeName,pInstance,Line,FileName);
        }
     }
  }
  
  BOOLEAN
  RxpTrackDereference(
        ULONG   TraceType,
        PCHAR   FileName,
        ULONG   Line,
        PVOID   pInstance)
  {
     PAGED_CODE();
  
     if (REF_TRACING_ON(TraceType)) {
        PCHAR pTypeName,pLogTypeName;
        ULONG RefCount;
  
        switch (TraceType) {
        case RDBSS_REF_TRACK_SRVCALL :
           pTypeName    = "SrvCall";
           pLogTypeName = "SC";
           RefCount     = ((PSRV_CALL)pInstance)->NodeReferenceCount;
           RxWmiLog(SRVCALL,RxDerefSrvcall,LOGPTR(pInstance)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
           break;
        case RDBSS_REF_TRACK_NETROOT :
           pTypeName = "NetRoot";
           pLogTypeName = "NR";
           RefCount     = ((PNET_ROOT)pInstance)->NodeReferenceCount;
           RxWmiLog(NETROOT,RxDerefNetRoot,LOGPTR(pInstance)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
           break;
        case RDBSS_REF_TRACK_VNETROOT:
           pTypeName = "VNetRoot";
           pLogTypeName = "VN";
           RefCount     = ((PV_NET_ROOT)pInstance)->NodeReferenceCount;
           RxWmiLog(VNETROOT,RxDerefVNetRoot,LOGPTR(pInstance)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
           break;
        case RDBSS_REF_TRACK_NETFOBX :
           pTypeName = "NetFobx";
           pLogTypeName = "FO";
           RefCount     = ((PFOBX)pInstance)->NodeReferenceCount;
           RxWmiLog(FOBX,RxDerefFobx,LOGPTR(pInstance)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
           break;
        case RDBSS_REF_TRACK_NETFCB  :
           pTypeName = "NetFcb";
           pLogTypeName = "FC";
           RefCount     = ((PFCB)pInstance)->NodeReferenceCount;
           RxWmiLog(FCB,RxDerefFcb,LOGPTR(pInstance)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
           break;
        case RDBSS_REF_TRACK_SRVOPEN :
           pTypeName = "SrvOpen";
           pLogTypeName = "SO";
           RefCount     = ((PSRV_OPEN)pInstance)->NodeReferenceCount;
           RxWmiLog(SRVOPEN,RxDerefSrvOpen,LOGPTR(pInstance)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
           break;
        default:
           DbgPrint("Invalid Node Type for referencing\n");
           //DbgBreakPoint();
           return TRUE;
        }
  
        if (RdbssReferenceTracingValue & RX_LOG_REF_TRACKING) {
           RxLog(("Deref.%s %lx %ld %lx %ld->%ld",pLogTypeName,pInstance,Line,FileName,RefCount,RefCount-1));
        }
  
        if (RdbssReferenceTracingValue & RX_PRINT_REF_TRACKING) {
           DbgPrint("Dereference %s %lx %ld %s\n",pTypeName,pInstance,Line,FileName);
        }
     }
     return TRUE;
  }
  
  #endif
  
  
  
  