2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
17 #include "afsd_init.h"
32 // The following is defined if you want to receive Power notifications,
33 // including Hibernation, and also subsequent flushing of AFS volumes
35 #define REGISTER_POWER_NOTIFICATIONS 1
36 #define FLUSH_VOLUME 1
40 #include "afsd_flushvol.h"
42 extern void afsi_log(char *pattern, ...);
44 HANDLE hAFSDMainThread = NULL;
46 HANDLE WaitToTerminate;
51 unsigned int MainThreadId;
55 extern int traceOnPanic;
56 extern HANDLE afsi_file;
58 int powerEventsRegistered = 0;
61 * Notifier function for use by osi_panic
63 static void afsd_notifier(char *msgp, char *filep, long line)
70 sprintf(tbuffer, "Error at file %s, line %d: %s",
73 sprintf(tbuffer, "Error at unknown location: %s", msgp);
75 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
77 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL);
78 DeregisterEventSource(h);
82 osi_LogEnable(afsd_logp);
84 afsd_ForceTrace(TRUE);
87 afsi_log("--- begin dump ---");
88 cm_DumpSCache(afsi_file, "a");
90 cm_dnlcDump(afsi_file, "a");
92 cm_DumpBufHashTable(afsi_file, "a");
93 smb_DumpVCP(afsi_file, "a");
94 afsi_log("--- end dump ---");
98 SetEvent(WaitToTerminate);
101 if (GetCurrentThreadId() == MainThreadId)
102 longjmp(notifier_jmp, 1);
109 * For use miscellaneously in smb.c; need to do better
111 static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
116 static SERVICE_STATUS ServiceStatus;
117 static SERVICE_STATUS_HANDLE StatusHandle;
120 afsd_ServiceFlushVolume(DWORD dwlpEventData)
122 DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
125 ** If UI bit is not set, user interaction is not possible
126 ** BUT, since we are a NON-interactive service, and therefore
127 ** have NO user I/O, it doesn't much matter.
128 ** This benign code left here as example of how to find this out
130 BOOL bUI = (dwlpEventData & 1);
133 if ( PowerNotificationThreadNotify() )
139 /* flush was unsuccessful, or timeout - deny shutdown */
140 dwRet = ERROR_NETWORK_BUSY;
143 /* to deny hibernate, simply return
144 // any value besides NO_ERROR.
146 // dwRet = ERROR_NETWORK_BUSY;
153 /* service control handler used in nt4 only for backward compat. */
155 afsd_ServiceControlHandler(DWORD ctrlCode)
158 DWORD dummyLen, doTrace;
162 case SERVICE_CONTROL_STOP:
164 RpcMgmtStopServerListening(NULL);
166 /* Force trace if requested */
167 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
169 0, KEY_QUERY_VALUE, &parmKey);
170 if (code != ERROR_SUCCESS)
173 dummyLen = sizeof(doTrace);
174 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
176 (BYTE *) &doTrace, &dummyLen);
177 RegCloseKey (parmKey);
178 if (code != ERROR_SUCCESS)
181 afsd_ForceTrace(FALSE);
182 buf_ForceTrace(FALSE);
186 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
187 ServiceStatus.dwWin32ExitCode = NO_ERROR;
188 ServiceStatus.dwCheckPoint = 1;
189 ServiceStatus.dwWaitHint = 10000;
190 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
191 SetServiceStatus(StatusHandle, &ServiceStatus);
192 SetEvent(WaitToTerminate);
194 case SERVICE_CONTROL_INTERROGATE:
195 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
196 ServiceStatus.dwWin32ExitCode = NO_ERROR;
197 ServiceStatus.dwCheckPoint = 0;
198 ServiceStatus.dwWaitHint = 0;
199 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
200 SetServiceStatus(StatusHandle, &ServiceStatus);
202 /* XXX handle system shutdown */
203 /* XXX handle pause & continue */
209 ** Extended ServiceControlHandler that provides Event types
210 ** for monitoring Power events, for example.
213 afsd_ServiceControlHandlerEx(
221 DWORD dummyLen, doTrace;
223 DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
227 case SERVICE_CONTROL_STOP:
229 RpcMgmtStopServerListening(NULL);
231 /* Force trace if requested */
232 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
234 0, KEY_QUERY_VALUE, &parmKey);
235 if (code != ERROR_SUCCESS)
238 dummyLen = sizeof(doTrace);
239 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
241 (BYTE *) &doTrace, &dummyLen);
242 RegCloseKey (parmKey);
243 if (code != ERROR_SUCCESS)
246 afsd_ForceTrace(FALSE);
247 buf_ForceTrace(FALSE);
251 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
252 ServiceStatus.dwWin32ExitCode = NO_ERROR;
253 ServiceStatus.dwCheckPoint = 1;
254 ServiceStatus.dwWaitHint = 10000;
255 ServiceStatus.dwControlsAccepted = 0;
256 SetServiceStatus(StatusHandle, &ServiceStatus);
257 SetEvent(WaitToTerminate);
261 case SERVICE_CONTROL_INTERROGATE:
262 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
263 ServiceStatus.dwWin32ExitCode = NO_ERROR;
264 ServiceStatus.dwCheckPoint = 0;
265 ServiceStatus.dwWaitHint = 0;
266 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
267 SetServiceStatus(StatusHandle, &ServiceStatus);
271 /* XXX handle system shutdown */
272 /* XXX handle pause & continue */
273 case SERVICE_CONTROL_POWEREVENT:
276 ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
277 ** Return NO_ERROR == return TRUE for that message, i.e. accept request
278 ** Return any error code to deny request,
279 ** i.e. as if returning BROADCAST_QUERY_DENY
281 if (powerEventsRegistered) {
282 switch((int) dwEventType)
284 case PBT_APMQUERYSUSPEND:
285 case PBT_APMQUERYSTANDBY:
289 dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);
295 /* allow remaining case PBT_WhatEver */
298 case PBT_APMRESUMECRITICAL:
299 case PBT_APMRESUMESUSPEND:
300 case PBT_APMRESUMESTANDBY:
301 case PBT_APMBATTERYLOW:
302 case PBT_APMPOWERSTATUSCHANGE:
303 case PBT_APMOEMEVENT:
304 case PBT_APMRESUMEAUTOMATIC:
310 } /* end switch(ctrlCode) */
314 /* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
316 * Mount a drive into AFS if there global mapping
318 /* DEE Could check first if we are run as SYSTEM */
319 #define MAX_RETRIES 30
320 static void MountGlobalDrives(void)
322 char szAfsPath[_MAX_PATH];
323 char szDriveToMapTo[5];
327 DWORD dwIndex = 0, dwRetry = 0;
329 DWORD dwSubMountSize;
330 char szSubMount[256];
333 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
335 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
336 if (dwResult != ERROR_SUCCESS)
339 while (dwRetry < MAX_RETRIES) {
340 dwDriveSize = sizeof(szDriveToMapTo);
341 dwSubMountSize = sizeof(szSubMount);
342 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
343 if (dwResult != ERROR_MORE_DATA) {
344 if (dwResult != ERROR_SUCCESS) {
345 if (dwResult != ERROR_NO_MORE_ITEMS)
346 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
351 for ( ; dwRetry < MAX_RETRIES; dwRetry++)
354 memset (&nr, 0x00, sizeof(NETRESOURCE));
356 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
358 nr.dwScope = RESOURCE_GLOBALNET; /* ignored parameter */
359 nr.dwType=RESOURCETYPE_DISK;
360 nr.lpLocalName=szDriveToMapTo;
361 nr.lpRemoteName=szAfsPath;
362 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; /* ignored parameter */
363 nr.dwUsage = RESOURCEUSAGE_CONNECTABLE; /* ignored parameter */
365 dwResult = WNetAddConnection2(&nr,NULL,NULL,0);
366 afsi_log("GlobalAutoMap of %s to %s %s (%d)", szDriveToMapTo, szSubMount,
367 (dwResult == NO_ERROR) ? "succeeded" : "failed", dwResult);
368 if (dwResult == NO_ERROR) {
371 /* wait for smb server to come up */
372 Sleep((DWORD)1000 /* miliseconds */);
374 /* Disconnect any previous mappings */
375 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
382 static void DismountGlobalDrives()
384 char szAfsPath[_MAX_PATH];
385 char szDriveToMapTo[5];
391 DWORD dwSubMountSize;
392 char szSubMount[256];
395 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
397 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
398 if (dwResult != ERROR_SUCCESS)
402 dwDriveSize = sizeof(szDriveToMapTo);
403 dwSubMountSize = sizeof(szSubMount);
404 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
405 if (dwResult != ERROR_MORE_DATA) {
406 if (dwResult != ERROR_SUCCESS) {
407 if (dwResult != ERROR_NO_MORE_ITEMS)
408 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
413 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
415 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
416 dwResult = WNetCancelConnection(szAfsPath, TRUE);
418 afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
424 typedef BOOL ( APIENTRY * AfsdInitHook )(void);
425 #define AFSD_INIT_HOOK "AfsdInitHook"
426 #define AFSD_HOOK_DLL "afsdhook.dll"
429 control serviceex exists only on 2000/xp. These functions will be loaded dynamically.
432 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerExFunc )( LPCTSTR , LPHANDLER_FUNCTION_EX , LPVOID );
433 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerFunc )( LPCTSTR , LPHANDLER_FUNCTION );
435 RegisterServiceCtrlHandlerExFunc pRegisterServiceCtrlHandlerEx = NULL;
436 RegisterServiceCtrlHandlerFunc pRegisterServiceCtrlHandler = NULL;
438 void afsd_Main(DWORD argc, LPTSTR *argv)
447 AfsdInitHook initHook;
450 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
451 _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
454 osi_InitPanic(afsd_notifier);
455 osi_InitTraceOption();
461 WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
462 if ( GetLastError() == ERROR_ALREADY_EXISTS )
463 afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
466 hAdvApi32 = LoadLibrary("advapi32.dll");
467 if (hAdvApi32 == NULL)
469 afsi_log("Fatal: cannot load advapi32.dll");
473 pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA");
474 if (pRegisterServiceCtrlHandlerEx)
476 afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx");
477 StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL );
481 StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
484 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
485 ServiceStatus.dwServiceSpecificExitCode = 0;
486 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
487 ServiceStatus.dwWin32ExitCode = NO_ERROR;
488 ServiceStatus.dwCheckPoint = 1;
489 ServiceStatus.dwWaitHint = 30000;
490 /* accept Power Events */
491 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
492 SetServiceStatus(StatusHandle, &ServiceStatus);
496 HANDLE h; char *ptbuf[1];
497 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
498 ptbuf[0] = "AFS start pending";
499 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
500 DeregisterEventSource(h);
503 #ifdef REGISTER_POWER_NOTIFICATIONS
510 /* see if we should handle power notifications */
511 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0, KEY_QUERY_VALUE, &hkParm);
512 if (code == ERROR_SUCCESS) {
513 dummyLen = sizeof(bpower);
514 code = RegQueryValueEx(hkParm, "FlushOnHibernate", NULL, NULL,
515 (BYTE *) &bpower, &dummyLen);
517 if(code != ERROR_SUCCESS)
522 /* create thread used to flush cache */
524 PowerNotificationThreadCreate();
525 powerEventsRegistered = 1;
530 /* allow an exit to be called prior to any initialization */
531 hInitHookDll = LoadLibrary(AFSD_HOOK_DLL);
535 initHook = ( AfsdInitHook ) GetProcAddress(hInitHookDll, AFSD_INIT_HOOK);
540 FreeLibrary(hInitHookDll);
545 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
546 ServiceStatus.dwWin32ExitCode = NO_ERROR;
547 ServiceStatus.dwCheckPoint = 0;
548 ServiceStatus.dwWaitHint = 0;
549 ServiceStatus.dwControlsAccepted = 0;
550 SetServiceStatus(StatusHandle, &ServiceStatus);
552 /* exit if initialization failed */
557 /* allow another 15 seconds to start */
558 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
559 ServiceStatus.dwServiceSpecificExitCode = 0;
560 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
561 ServiceStatus.dwWin32ExitCode = NO_ERROR;
562 ServiceStatus.dwCheckPoint = 2;
563 ServiceStatus.dwWaitHint = 20000;
564 /* accept Power Events */
565 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
566 SetServiceStatus(StatusHandle, &ServiceStatus);
571 MainThreadId = GetCurrentThreadId();
572 jmpret = setjmp(notifier_jmp);
577 code = afsd_InitCM(&reason);
579 afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
580 osi_panic(reason, __FILE__, __LINE__);
584 ServiceStatus.dwCheckPoint++;
585 ServiceStatus.dwWaitHint -= 5000;
586 SetServiceStatus(StatusHandle, &ServiceStatus);
588 code = afsd_InitDaemons(&reason);
590 afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
591 osi_panic(reason, __FILE__, __LINE__);
595 ServiceStatus.dwCheckPoint++;
596 ServiceStatus.dwWaitHint -= 5000;
597 SetServiceStatus(StatusHandle, &ServiceStatus);
599 code = afsd_InitSMB(&reason, MessageBox);
601 afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
602 osi_panic(reason, __FILE__, __LINE__);
608 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
609 ServiceStatus.dwWin32ExitCode = NO_ERROR;
610 ServiceStatus.dwCheckPoint = 0;
611 ServiceStatus.dwWaitHint = 0;
613 /* accept Power events */
614 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
615 SetServiceStatus(StatusHandle, &ServiceStatus);
618 HANDLE h; char *ptbuf[1];
619 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
620 ptbuf[0] = "AFS running";
621 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
622 DeregisterEventSource(h);
626 WaitForSingleObject(WaitToTerminate, INFINITE);
629 HANDLE h; char *ptbuf[1];
630 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
631 ptbuf[0] = "AFS quitting";
632 ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
633 0, 0, NULL, 1, 0, ptbuf, NULL);
634 DeregisterEventSource(h);
637 DismountGlobalDrives();
641 #ifdef REGISTER_POWER_NOTIFICATIONS
642 /* terminate thread used to flush cache */
643 if (powerEventsRegistered)
644 PowerNotificationThreadExit();
647 /* Remove the ExceptionFilter */
648 SetUnhandledExceptionFilter(NULL);
650 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
651 ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
652 ServiceStatus.dwCheckPoint = 0;
653 ServiceStatus.dwWaitHint = 0;
654 ServiceStatus.dwControlsAccepted = 0;
655 SetServiceStatus(StatusHandle, &ServiceStatus);
658 DWORD __stdcall afsdMain_thread(void* notUsed)
660 char * argv[2] = {AFS_DAEMON_SERVICE_NAME, NULL};
661 afsd_Main(1, (LPTSTR*)argv);
668 static SERVICE_TABLE_ENTRY dispatchTable[] = {
669 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
673 if (!StartServiceCtrlDispatcher(dispatchTable))
675 LONG status = GetLastError();
676 if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
679 hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
681 printf("Hit <Enter> to terminate OpenAFS Client Service\n");
683 SetEvent(WaitToTerminate);
687 if ( hAFSDMainThread ) {
688 WaitForSingleObject( hAFSDMainThread, INFINITE );
689 CloseHandle( hAFSDMainThread );