Windows: move debug break in afsd_notifier
[openafs.git] / src / WINNT / afsd / afsd_service.c
index d755f5e..b7bb6a4 100644 (file)
@@ -14,6 +14,9 @@
 #include <stdlib.h>
 #include <winsock2.h>
 #include <WINNT\afsreg.h>
+#include "cm_btree.h"
+#include "cm_rpc.h"
+#include "smb.h"
 
 #include <osi.h>
 
@@ -23,7 +26,6 @@
 #ifdef _DEBUG
 #include <crtdbg.h>
 #endif
-#include "afsdifs.h"
 
 //#define REGISTER_POWER_NOTIFICATIONS 1
 #include "afsd_flushvol.h"
@@ -32,15 +34,13 @@ extern void afsi_log(char *pattern, ...);
 
 static SERVICE_STATUS          ServiceStatus;
 static SERVICE_STATUS_HANDLE   StatusHandle;
+static BOOL bRunningAsService = TRUE;
 
 HANDLE hAFSDMainThread = NULL;
-#ifdef AFSIFS
-HANDLE hAFSDWorkerThread[WORKER_THREADS];
-#endif
 
 HANDLE WaitToTerminate;
 
-int GlobalStatus;
+static int GlobalStatus;
 
 #ifdef JUMP
 unsigned int MainThreadId;
@@ -50,16 +50,20 @@ jmp_buf notifier_jmp;
 extern int traceOnPanic;
 extern HANDLE afsi_file;
 
-int powerEventsRegistered = 0;
+static int powerEventsRegistered = 0;
+extern int powerStateSuspended = 0;
+
+static VOID (WINAPI* pRtlCaptureContext)(PCONTEXT ContextRecord) = NULL;
 
 /*
  * Notifier function for use by osi_panic
  */
 static void afsd_notifier(char *msgp, char *filep, long line)
 {
-#ifdef AFSIFS
-    int i;
-#endif
+    CONTEXT context;
+
+    if (!msgp)
+        msgp = "unspecified assert";
 
     if (filep)
        LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP_WITH_MSG_AND_LOCATION, 
@@ -74,39 +78,46 @@ static void afsd_notifier(char *msgp, char *filep, long line)
     afsd_ForceTrace(TRUE);
     buf_ForceTrace(TRUE);
 
+    if (pRtlCaptureContext) {
+        pRtlCaptureContext(&context);
+        afsd_printStack(GetCurrentThread(), &context);
+    }
+
+#ifdef DEBUG
+    if (IsDebuggerPresent())
+        DebugBreak();
+#endif
+
     afsi_log("--- begin dump ---");
+    cm_MemDumpDirStats(afsi_file, "a", 0);
+    cm_MemDumpBPlusStats(afsi_file, "a", 0);
+    cm_DumpCells(afsi_file, "a", 0);
+    cm_DumpVolumes(afsi_file, "a", 0);
     cm_DumpSCache(afsi_file, "a", 0);
-#ifdef keisa
-    cm_dnlcDump(afsi_file, "a");
-#endif
     cm_DumpBufHashTable(afsi_file, "a", 0);
+    cm_DumpServers(afsi_file, "a", 0);
     smb_DumpVCP(afsi_file, "a", 0);                    
+    rx_DumpPackets(afsi_file, "a");
+    rx_DumpCalls(afsi_file, "a");
     afsi_log("--- end   dump ---");
     
-#ifdef DEBUG
-       if (IsDebuggerPresent())
-               DebugBreak();   
-#endif
+    GenerateMiniDump(NULL);
 
     SetEvent(WaitToTerminate);
-#ifdef AFSIFS
-    WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE);
-    for (i = 0; i < WORKER_THREADS; i++)
-        CloseHandle(hAFSDWorkerThread[i]);
-#endif
 
 #ifdef JUMP
     if (GetCurrentThreadId() == MainThreadId)
         longjmp(notifier_jmp, 1);
 #endif /* JUMP */
 
-    ServiceStatus.dwCurrentState = SERVICE_STOPPED;
-    ServiceStatus.dwWin32ExitCode = NO_ERROR;
-    ServiceStatus.dwCheckPoint = 0;
-    ServiceStatus.dwWaitHint = 0;
-    ServiceStatus.dwControlsAccepted = 0;
-    SetServiceStatus(StatusHandle, &ServiceStatus);
-
+    if (bRunningAsService) {
+        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+        ServiceStatus.dwWin32ExitCode = NO_ERROR;
+        ServiceStatus.dwCheckPoint = 0;
+        ServiceStatus.dwWaitHint = 0;
+        ServiceStatus.dwControlsAccepted = 0;
+        SetServiceStatus(StatusHandle, &ServiceStatus);
+    }
     exit(1);
 }
 
@@ -232,11 +243,22 @@ afsd_ServiceControlHandlerEx(
     DWORD dummyLen, doTrace;
     long code;
     DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
+    OSVERSIONINFO osVersion;
+
+    /* Get the version of Windows */
+    memset(&osVersion, 0x00, sizeof(osVersion));
+    osVersion.dwOSVersionInfoSize = sizeof(osVersion);
+    GetVersionEx(&osVersion);
 
     switch (ctrlCode) 
     {
     case SERVICE_CONTROL_SHUTDOWN:
     case SERVICE_CONTROL_STOP:
+       if (ctrlCode == SERVICE_CONTROL_SHUTDOWN)
+           afsi_log("SERVICE_CONTROL_SHUTDOWN");
+       else
+            afsi_log("SERVICE_CONTROL_STOP");
+
         ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
         ServiceStatus.dwWin32ExitCode = NO_ERROR;
         ServiceStatus.dwCheckPoint = 1;
@@ -302,38 +324,56 @@ afsd_ServiceControlHandlerEx(
                 case PBT_APMQUERYSUSPEND:       
                     afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND"); 
                     /* Write all dirty buffers back to server */
-                   if ( !lana_OnlyLoopback() )
+                   if ( !lana_OnlyLoopback() ) {
                        buf_CleanAndReset();
+                        cm_SuspendSCache();
+                    }
                     afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND buf_CleanAndReset complete"); 
                     dwRet = NO_ERROR;                       
                     break;                                  
                 case PBT_APMQUERYSTANDBY:                                                         
                     afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY"); 
                     /* Write all dirty buffers back to server */
-                   if ( !lana_OnlyLoopback() ) 
+                   if ( !lana_OnlyLoopback() ) {
                        buf_CleanAndReset();
+                        cm_SuspendSCache();
+                    }
                     afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY buf_CleanAndReset complete"); 
                     dwRet = NO_ERROR;                                                             
                     break;                                                                        
                                                                                                                          
                     /* allow remaining case PBT_WhatEver */                                           
                 case PBT_APMSUSPEND:                         
-                    afsi_log("SERVICE_CONTROL_APMSUSPEND"); 
+                    afsi_log("SERVICE_CONTROL_APMSUSPEND");
+                   powerStateSuspended = 1;
+                   if (osVersion.dwMajorVersion >= 6) {
+                        cm_SuspendSCache();
+                       smb_StopListeners(0);
+                    }
                     dwRet = NO_ERROR;                       
                     break;                                  
                 case PBT_APMSTANDBY:                  
                     afsi_log("SERVICE_CONTROL_APMSTANDBY"); 
+                   powerStateSuspended = 1;
+                   if (osVersion.dwMajorVersion >= 6) {
+                        cm_SuspendSCache();
+                       smb_StopListeners(0);
+                    }
                     dwRet = NO_ERROR;                       
                     break;                                  
                 case PBT_APMRESUMECRITICAL:             
                     afsi_log("SERVICE_CONTROL_APMRESUMECRITICAL"); 
+                   if (osVersion.dwMajorVersion >= 6)
+                       smb_RestartListeners(0);
                     dwRet = NO_ERROR;                       
                     break;                                  
                 case PBT_APMRESUMESUSPEND:                                                        
+                   /* User logged in after suspend */
                     afsi_log("SERVICE_CONTROL_APMRESUMESUSPEND"); 
                     dwRet = NO_ERROR;                       
                     break;                                  
-                case PBT_APMRESUMESTANDBY:                                                        
+                case PBT_APMRESUMESTANDBY:            
+                   /* User logged in after standby */
                     afsi_log("SERVICE_CONTROL_APMRESUMESTANDBY"); 
                     dwRet = NO_ERROR;                       
                     break;                                  
@@ -353,8 +393,13 @@ afsd_ServiceControlHandlerEx(
 #endif
                     dwRet = NO_ERROR;                       
                     break;                                  
-                case PBT_APMRESUMEAUTOMATIC:                                                      
+                case PBT_APMRESUMEAUTOMATIC:          
+                   /* This is the message delivered once all devices are up */
                     afsi_log("SERVICE_CONTROL_APMRESUMEAUTOMATIC"); 
+                   powerStateSuspended = 0;
+                   if (osVersion.dwMajorVersion >= 6) {
+                       smb_SetLanAdapterChangeDetected();
+                    }
                     dwRet = NO_ERROR;                       
                     break;                                  
                 default:                                                                          
@@ -384,9 +429,7 @@ afsd_ServiceControlHandlerEx(
 #define MAX_DRIVES  23
 static DWORD __stdcall MountGlobalDrivesThread(void * notUsed)
 {
-#ifndef AFSIFS
     char szAfsPath[_MAX_PATH];
-#endif
     char szDriveToMapTo[5];
     DWORD dwResult;
     char szKeyName[256];
@@ -401,7 +444,7 @@ static DWORD __stdcall MountGlobalDrivesThread(void * notUsed)
 
     dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
     if (dwResult != ERROR_SUCCESS)
-        return;
+        return 0;
 
     while (dwIndex < MAX_DRIVES) {
         dwDriveSize = sizeof(szDriveToMapTo);
@@ -415,7 +458,6 @@ static DWORD __stdcall MountGlobalDrivesThread(void * notUsed)
             }
         }
 
-#ifndef AFSIFS
         for (dwRetry = 0 ; dwRetry < MAX_RETRIES; dwRetry++)
         {
             NETRESOURCE nr;
@@ -425,7 +467,7 @@ static DWORD __stdcall MountGlobalDrivesThread(void * notUsed)
 
             nr.dwScope = RESOURCE_GLOBALNET;              /* ignored parameter */
             nr.dwType=RESOURCETYPE_DISK;
-            nr.lpLocalName=szDriveToMapTo;
+            nr.lpLocalName=strlen(szDriveToMapTo) > 0 ? szDriveToMapTo : NULL;
             nr.lpRemoteName=szAfsPath;
             nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; /* ignored parameter */
             nr.dwUsage = RESOURCEUSAGE_CONNECTABLE;       /* ignored parameter */
@@ -442,10 +484,6 @@ static DWORD __stdcall MountGlobalDrivesThread(void * notUsed)
             /* Disconnect any previous mappings */
             dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
         }
-#else
-       /* FIXFIX: implement */
-       afsi_log("GlobalAutoMap of %s to %s not implemented", szDriveToMapTo, szSubMount);
-#endif
     }        
 
     RegCloseKey(hKey);
@@ -474,14 +512,12 @@ static void MountGlobalDrives()
 
 static void DismountGlobalDrives()
 {
-#ifndef AFSIFS
     char szAfsPath[_MAX_PATH];
     char szDriveToMapTo[5];
     DWORD dwDriveSize;
     DWORD dwSubMountSize;
     char szSubMount[256];
     DWORD dwType;
-#endif
     DWORD dwResult;
     char szKeyName[256];
     HKEY hKey;
@@ -506,9 +542,6 @@ static void DismountGlobalDrives()
     if (dwResult != ERROR_SUCCESS)
         return;
 
-#ifdef AFSIFS    
-    /* FIXFIX: implement */
-#else
     while (dwIndex < MAX_DRIVES) {
         dwDriveSize = sizeof(szDriveToMapTo);
         dwSubMountSize = sizeof(szSubMount);
@@ -528,7 +561,6 @@ static void DismountGlobalDrives()
         
         afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
     }        
-#endif
 
     RegCloseKey(hKey);
 }
@@ -965,7 +997,11 @@ BOOL AFSModulesVerify(void)
         RegCloseKey (parmKey);
     }
 
-    if (verifyServiceSig && cacheSize < 716800) {
+    if (verifyServiceSig 
+#ifndef _WIN64
+         && cacheSize < 716800
+#endif
+         ) {
         trustVerified = VerifyTrust(filename);
     } else {
         afsi_log("Signature Verification disabled");
@@ -1072,11 +1108,11 @@ afsd_Main(DWORD argc, LPTSTR *argv)
 #endif /* JUMP */
     HMODULE hHookDll;
     HMODULE hAdvApi32;
-#ifdef AFSIFS
-    int cnt;
-#endif
+    HMODULE hKernel32;
 
 #ifdef _DEBUG
+    void afsd_DbgBreakAllocInit();
+
     afsd_DbgBreakAllocInit();
     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ | 
                    _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
@@ -1087,6 +1123,14 @@ afsd_Main(DWORD argc, LPTSTR *argv)
     osi_InitPanic(afsd_notifier);
     osi_InitTraceOption();
 
+    hKernel32 = LoadLibrary("kernel32.dll");
+    if (hKernel32 == NULL)
+    {
+        afsi_log("Fatal: cannot load kernel32.dll");
+        return;
+    }
+    pRtlCaptureContext = GetProcAddress(hKernel32, "RtlCaptureContext");
+
     GlobalStatus = 0;
 
     afsi_start();
@@ -1103,26 +1147,28 @@ afsd_Main(DWORD argc, LPTSTR *argv)
         return;
     }
 
-    pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA");
-    if (pRegisterServiceCtrlHandlerEx)
-    {
-        afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx");
-        StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL );
-    }
-    else
-    {
-        StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
-    }
+    if (bRunningAsService) {
+        pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA");
+        if (pRegisterServiceCtrlHandlerEx)
+        {
+            afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx");
+            StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL );
+        }
+        else
+        {
+            StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
+        }
 
-    ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
-    ServiceStatus.dwServiceSpecificExitCode = 0;
-    ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
-    ServiceStatus.dwWin32ExitCode = NO_ERROR;
-    ServiceStatus.dwCheckPoint = 1;
-    ServiceStatus.dwWaitHint = 30000;
-    /* accept Power Events */
-    ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
-    SetServiceStatus(StatusHandle, &ServiceStatus);
+        ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+        ServiceStatus.dwServiceSpecificExitCode = 0;
+        ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
+        ServiceStatus.dwWin32ExitCode = NO_ERROR;
+        ServiceStatus.dwCheckPoint = 1;
+        ServiceStatus.dwWaitHint = 120000;
+        /* accept Power Events */
+        ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
+        SetServiceStatus(StatusHandle, &ServiceStatus);
+    }
 #endif
 
     LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_START_PENDING);
@@ -1157,13 +1203,14 @@ afsd_Main(DWORD argc, LPTSTR *argv)
 
     /* Verify the versions of the DLLs which were loaded */
     if (!AFSModulesVerify()) {
-        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
-        ServiceStatus.dwWin32ExitCode = NO_ERROR;
-        ServiceStatus.dwCheckPoint = 0;
-        ServiceStatus.dwWaitHint = 0;
-        ServiceStatus.dwControlsAccepted = 0;
-        SetServiceStatus(StatusHandle, &ServiceStatus);
-
+        if (bRunningAsService) {
+            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+            ServiceStatus.dwWin32ExitCode = NO_ERROR;
+            ServiceStatus.dwCheckPoint = 0;
+            ServiceStatus.dwWaitHint = 0;
+            ServiceStatus.dwControlsAccepted = 0;
+            SetServiceStatus(StatusHandle, &ServiceStatus);
+        }
        LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_INCORRECT_VERSIONS);
 
         /* exit if initialization failed */
@@ -1171,7 +1218,7 @@ afsd_Main(DWORD argc, LPTSTR *argv)
     }
 
     /* allow an exit to be called prior to any initialization */
-    hHookDll = LoadLibrary(AFSD_HOOK_DLL);
+    hHookDll = cm_LoadAfsdHookLib();
     if (hHookDll)
     {
         BOOL hookRc = TRUE;
@@ -1185,31 +1232,37 @@ afsd_Main(DWORD argc, LPTSTR *argv)
 
         if (hookRc == FALSE)
         {
-            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
-            ServiceStatus.dwWin32ExitCode = NO_ERROR;
-            ServiceStatus.dwCheckPoint = 0;
-            ServiceStatus.dwWaitHint = 0;
-            ServiceStatus.dwControlsAccepted = 0;
-            SetServiceStatus(StatusHandle, &ServiceStatus);
-                       
+            if (bRunningAsService) {
+                ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+                ServiceStatus.dwWin32ExitCode = NO_ERROR;
+                ServiceStatus.dwCheckPoint = 0;
+                ServiceStatus.dwWaitHint = 0;
+                ServiceStatus.dwControlsAccepted = 0;
+                SetServiceStatus(StatusHandle, &ServiceStatus);
+            }       
             /* exit if initialization failed */
             return;
         }
         else
         {
-            /* allow another 15 seconds to start */
-            ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
-            ServiceStatus.dwServiceSpecificExitCode = 0;
-            ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
-            ServiceStatus.dwWin32ExitCode = NO_ERROR;
-            ServiceStatus.dwCheckPoint = 2;
-            ServiceStatus.dwWaitHint = 20000;
-            /* accept Power Events */
-            ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
-            SetServiceStatus(StatusHandle, &ServiceStatus);
+            /* allow another 120 seconds to start */
+            if (bRunningAsService) {
+                ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+                ServiceStatus.dwServiceSpecificExitCode = 0;
+                ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
+                ServiceStatus.dwWin32ExitCode = NO_ERROR;
+                ServiceStatus.dwCheckPoint = 2;
+                ServiceStatus.dwWaitHint = 120000;
+                /* accept Power Events */
+                ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
+                SetServiceStatus(StatusHandle, &ServiceStatus);
+            }
         }
     }
 
+    /* Perform Volume Status Notification Initialization */
+    cm_VolStatus_Initialization();
+
 #ifdef JUMP
     MainThreadId = GetCurrentThreadId();
     jmpret = setjmp(notifier_jmp);
@@ -1224,18 +1277,14 @@ afsd_Main(DWORD argc, LPTSTR *argv)
         }
 
 #ifndef NOTSERVICE
-        ServiceStatus.dwCheckPoint++;
-        ServiceStatus.dwWaitHint -= 5000;
-        SetServiceStatus(StatusHandle, &ServiceStatus);
-#endif
-        code = afsd_InitDaemons(&reason);
-        if (code != 0) {
-            afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
-                       osi_panic(reason, __FILE__, __LINE__);
+        if (bRunningAsService) {
+            ServiceStatus.dwCheckPoint = 3;
+            ServiceStatus.dwWaitHint = 30000;
+            SetServiceStatus(StatusHandle, &ServiceStatus);
         }
-
+#endif
         /* allow an exit to be called post rx initialization */
-        hHookDll = LoadLibrary(AFSD_HOOK_DLL);
+        hHookDll = cm_LoadAfsdHookLib();
         if (hHookDll)
         {
             BOOL hookRc = TRUE;
@@ -1249,45 +1298,38 @@ afsd_Main(DWORD argc, LPTSTR *argv)
 
             if (hookRc == FALSE)
             {
-                ServiceStatus.dwCurrentState = SERVICE_STOPPED;
-                ServiceStatus.dwWin32ExitCode = NO_ERROR;
-                ServiceStatus.dwCheckPoint = 0;
-                ServiceStatus.dwWaitHint = 0;
-                ServiceStatus.dwControlsAccepted = 0;
-                SetServiceStatus(StatusHandle, &ServiceStatus);
-                       
+                if (bRunningAsService) {
+                    ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+                    ServiceStatus.dwWin32ExitCode = NO_ERROR;
+                    ServiceStatus.dwCheckPoint = 0;
+                    ServiceStatus.dwWaitHint = 0;
+                    ServiceStatus.dwControlsAccepted = 0;
+                    SetServiceStatus(StatusHandle, &ServiceStatus);
+                }   
                 /* exit if initialization failed */
                 return;
             }
         }
 
 #ifndef NOTSERVICE
-        ServiceStatus.dwCheckPoint++;
-        ServiceStatus.dwWaitHint -= 5000;
-        SetServiceStatus(StatusHandle, &ServiceStatus);
+        if (bRunningAsService) {
+            ServiceStatus.dwCheckPoint = 4;
+            ServiceStatus.dwWaitHint = 15000;
+            SetServiceStatus(StatusHandle, &ServiceStatus);
+        }
 #endif
 
-/* the following ifdef chooses the mode of operation for the service.  to enable
- * a runtime flag (instead of compile-time), pioctl() would need to dynamically
- * determine the mode, in order to use the correct ioctl special-file path. */
-#ifndef AFSIFS
+        /* Notify any volume status handlers that the cache manager has started */
+        cm_VolStatus_Service_Started();
+
         code = afsd_InitSMB(&reason, MessageBox);
         if (code != 0) {
             afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
             osi_panic(reason, __FILE__, __LINE__);
         }
-#else
-        code = ifs_Init(&reason);
-        if (code != 0) {
-            afsi_log("ifs_Init failed: %s (code = %d)", reason, code);
-            osi_panic(reason, __FILE__, __LINE__);
-        }     
-        for (cnt = 0; cnt < WORKER_THREADS; cnt++)
-            hAFSDWorkerThread[cnt] = CreateThread(NULL, 0, ifs_MainLoop, 0, 0, NULL);
-#endif  
 
         /* allow an exit to be called post smb initialization */
-        hHookDll = LoadLibrary(AFSD_HOOK_DLL);
+        hHookDll = cm_LoadAfsdHookLib();
         if (hHookDll)
         {
             BOOL hookRc = TRUE;
@@ -1301,13 +1343,14 @@ afsd_Main(DWORD argc, LPTSTR *argv)
 
             if (hookRc == FALSE)
             {
-                ServiceStatus.dwCurrentState = SERVICE_STOPPED;
-                ServiceStatus.dwWin32ExitCode = NO_ERROR;
-                ServiceStatus.dwCheckPoint = 0;
-                ServiceStatus.dwWaitHint = 0;
-                ServiceStatus.dwControlsAccepted = 0;
-                SetServiceStatus(StatusHandle, &ServiceStatus);
-                       
+                if (bRunningAsService) {
+                    ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+                    ServiceStatus.dwWin32ExitCode = NO_ERROR;
+                    ServiceStatus.dwCheckPoint = 0;
+                    ServiceStatus.dwWaitHint = 0;
+                    ServiceStatus.dwControlsAccepted = 0;
+                    SetServiceStatus(StatusHandle, &ServiceStatus);
+                }   
                 /* exit if initialization failed */
                 return;
             }
@@ -1315,22 +1358,30 @@ afsd_Main(DWORD argc, LPTSTR *argv)
 
         MountGlobalDrives();
 
+        code = afsd_InitDaemons(&reason);
+        if (code != 0) {
+            afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
+                       osi_panic(reason, __FILE__, __LINE__);
+        }
+
 #ifndef NOTSERVICE
-        ServiceStatus.dwCurrentState = SERVICE_RUNNING;
-        ServiceStatus.dwWin32ExitCode = NO_ERROR;
-        ServiceStatus.dwCheckPoint = 0;
-        ServiceStatus.dwWaitHint = 0;
+        if (bRunningAsService) {
+            ServiceStatus.dwCurrentState = SERVICE_RUNNING;
+            ServiceStatus.dwWin32ExitCode = NO_ERROR;
+            ServiceStatus.dwCheckPoint = 5;
+            ServiceStatus.dwWaitHint = 0;
 
-        /* accept Power events */
-        ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
-        SetServiceStatus(StatusHandle, &ServiceStatus);
+            /* accept Power events */
+            ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
+            SetServiceStatus(StatusHandle, &ServiceStatus);
+        }
 #endif  
 
        LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_RUNNING);
     }
 
     /* allow an exit to be called when started */
-    hHookDll = LoadLibrary(AFSD_HOOK_DLL);
+    hHookDll = cm_LoadAfsdHookLib();
     if (hHookDll)
     {
         BOOL hookRc = TRUE;
@@ -1344,26 +1395,29 @@ afsd_Main(DWORD argc, LPTSTR *argv)
 
         if (hookRc == FALSE)
         {
-            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
-            ServiceStatus.dwWin32ExitCode = NO_ERROR;
-            ServiceStatus.dwCheckPoint = 0;
-            ServiceStatus.dwWaitHint = 0;
-            ServiceStatus.dwControlsAccepted = 0;
-            SetServiceStatus(StatusHandle, &ServiceStatus);
-                       
+            if (bRunningAsService) {
+                ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+                ServiceStatus.dwWin32ExitCode = NO_ERROR;
+                ServiceStatus.dwCheckPoint = 0;
+                ServiceStatus.dwWaitHint = 0;
+                ServiceStatus.dwControlsAccepted = 0;
+                SetServiceStatus(StatusHandle, &ServiceStatus);
+            }                       
             /* exit if initialization failed */
             return;
         }
     }
 
-#ifndef AFSIFS
     WaitForSingleObject(WaitToTerminate, INFINITE);
-#else
-    WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE);
-    for (cnt = 0; cnt < WORKER_THREADS; cnt++)
-        CloseHandle(hAFSDWorkerThread[cnt]);
-#endif
 
+    if (bRunningAsService) {
+        ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
+        ServiceStatus.dwWin32ExitCode = NO_ERROR;
+        ServiceStatus.dwCheckPoint = 6;
+        ServiceStatus.dwWaitHint = 120000;
+        ServiceStatus.dwControlsAccepted = 0;
+        SetServiceStatus(StatusHandle, &ServiceStatus);
+    }
     afsi_log("Received Termination Signal, Stopping Service");
 
     if ( GlobalStatus )
@@ -1372,7 +1426,7 @@ afsd_Main(DWORD argc, LPTSTR *argv)
        LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_STOPPING);
 
     /* allow an exit to be called prior to stopping the service */
-    hHookDll = LoadLibrary(AFSD_HOOK_DLL);
+    hHookDll = cm_LoadAfsdHookLib();
     if (hHookDll)
     {
         BOOL hookRc = TRUE;
@@ -1383,19 +1437,6 @@ afsd_Main(DWORD argc, LPTSTR *argv)
         }
         FreeLibrary(hHookDll);
         hHookDll = NULL;
-
-        if (hookRc == FALSE)
-        {
-            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
-            ServiceStatus.dwWin32ExitCode = NO_ERROR;
-            ServiceStatus.dwCheckPoint = 0;
-            ServiceStatus.dwWaitHint = 0;
-            ServiceStatus.dwControlsAccepted = 0;
-            SetServiceStatus(StatusHandle, &ServiceStatus);
-                       
-            /* exit if initialization failed */
-            return;
-        }
     }
 
 
@@ -1407,39 +1448,45 @@ afsd_Main(DWORD argc, LPTSTR *argv)
     DismountGlobalDrives();
     afsi_log("Global Drives dismounted");
                                          
+    smb_Shutdown();                      
+    afsi_log("smb shutdown complete");   
+                                         
+    RpcShutdown();                       
+
+    cm_ReleaseAllLocks();
+
     cm_DaemonShutdown();                 
     afsi_log("Daemon shutdown complete");
     
-    afsd_ShutdownCM();
-
     buf_Shutdown();                      
     afsi_log("Buffer shutdown complete");
                                          
-    rx_Finalize();                       
-    afsi_log("rx finalization complete");
-                                         
-#ifndef AFSIFS
-    smb_Shutdown();                      
-    afsi_log("smb shutdown complete");   
-#endif
-                                         
-    RpcShutdown();                       
+    afsd_ShutdownCM();
 
-    cm_ReleaseAllLocks();
+    cm_ShutdownMappedMemory();           
 
     rx_Finalize();
     afsi_log("rx finalization complete");
 
-    cm_ShutdownMappedMemory();           
-
 #ifdef REGISTER_POWER_NOTIFICATIONS
     /* terminate thread used to flush cache */
     if (powerEventsRegistered)
         PowerNotificationThreadExit();
 #endif
 
+    cm_DirDumpStats();
+#ifdef USE_BPLUS
+    cm_BPlusDumpStats();
+#endif
+
+    /* Notify any Volume Status Handlers that we are stopped */
+    cm_VolStatus_Service_Stopped();
+
+    /* Cleanup any Volume Status Notification Handler */
+    cm_VolStatus_Finalize();
+
     /* allow an exit to be called after stopping the service */
-    hHookDll = LoadLibrary(AFSD_HOOK_DLL);
+    hHookDll = cm_LoadAfsdHookLib();
     if (hHookDll)
     {
         BOOL hookRc = TRUE;
@@ -1455,12 +1502,14 @@ afsd_Main(DWORD argc, LPTSTR *argv)
     /* Remove the ExceptionFilter */
     SetUnhandledExceptionFilter(NULL);
 
-    ServiceStatus.dwCurrentState = SERVICE_STOPPED;
-    ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
-    ServiceStatus.dwCheckPoint = 0;
-    ServiceStatus.dwWaitHint = 0;
-    ServiceStatus.dwControlsAccepted = 0;
-    SetServiceStatus(StatusHandle, &ServiceStatus);
+    if (bRunningAsService) {
+        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+        ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
+        ServiceStatus.dwCheckPoint = 7;
+        ServiceStatus.dwWaitHint = 0;
+        ServiceStatus.dwControlsAccepted = 0;
+        SetServiceStatus(StatusHandle, &ServiceStatus);
+    }
 }       
 
 DWORD __stdcall afsdMain_thread(void* notUsed)
@@ -1504,14 +1553,14 @@ main(int argc, char * argv[])
         if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
         {
             DWORD tid;
+
+            bRunningAsService = FALSE;
+
             hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
                
             printf("Hit <Enter> to terminate OpenAFS Client Service\n");
             getchar();  
             SetEvent(WaitToTerminate);
-#ifdef AFSIFS
-           dc_release_hooks();
-#endif
         }
     }