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 powerEventsRegsitered = 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);
86 afsi_log("--- begin dump ---");
87 cm_DumpSCache(afsi_file, "a");
89 cm_dnlcDump(afsi_file, "a");
91 cm_DumpBufHashTable(afsi_file, "a");
92 smb_DumpVCP(afsi_file, "a");
93 afsi_log("--- end dump ---");
97 SetEvent(WaitToTerminate);
100 if (GetCurrentThreadId() == MainThreadId)
101 longjmp(notifier_jmp, 1);
108 * For use miscellaneously in smb.c; need to do better
110 static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
115 static SERVICE_STATUS ServiceStatus;
116 static SERVICE_STATUS_HANDLE StatusHandle;
119 afsd_ServiceFlushVolume(DWORD dwlpEventData)
121 DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
124 ** If UI bit is not set, user interaction is not possible
125 ** BUT, since we are a NON-interactive service, and therefore
126 ** have NO user I/O, it doesn't much matter.
127 ** This benign code left here as example of how to find this out
129 BOOL bUI = (dwlpEventData & 1);
132 if ( PowerNotificationThreadNotify() )
138 /* flush was unsuccessful, or timeout - deny shutdown */
139 dwRet = ERROR_NETWORK_BUSY;
142 /* to deny hibernate, simply return
143 // any value besides NO_ERROR.
145 // dwRet = ERROR_NETWORK_BUSY;
152 /* service control handler used in nt4 only for backward compat. */
154 afsd_ServiceControlHandler(DWORD ctrlCode)
157 DWORD dummyLen, doTrace;
161 case SERVICE_CONTROL_STOP:
163 RpcMgmtStopServerListening(NULL);
165 /* Force trace if requested */
166 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
168 0, KEY_QUERY_VALUE, &parmKey);
169 if (code != ERROR_SUCCESS)
172 dummyLen = sizeof(doTrace);
173 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
175 (BYTE *) &doTrace, &dummyLen);
176 RegCloseKey (parmKey);
177 if (code != ERROR_SUCCESS)
180 afsd_ForceTrace(FALSE);
183 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
184 ServiceStatus.dwWin32ExitCode = NO_ERROR;
185 ServiceStatus.dwCheckPoint = 1;
186 ServiceStatus.dwWaitHint = 10000;
187 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
188 SetServiceStatus(StatusHandle, &ServiceStatus);
189 SetEvent(WaitToTerminate);
191 case SERVICE_CONTROL_INTERROGATE:
192 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
193 ServiceStatus.dwWin32ExitCode = NO_ERROR;
194 ServiceStatus.dwCheckPoint = 0;
195 ServiceStatus.dwWaitHint = 0;
196 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
197 SetServiceStatus(StatusHandle, &ServiceStatus);
199 /* XXX handle system shutdown */
200 /* XXX handle pause & continue */
206 ** Extended ServiceControlHandler that provides Event types
207 ** for monitoring Power events, for example.
210 afsd_ServiceControlHandlerEx(
218 DWORD dummyLen, doTrace;
220 DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
224 case SERVICE_CONTROL_STOP:
226 RpcMgmtStopServerListening(NULL);
228 /* Force trace if requested */
229 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
231 0, KEY_QUERY_VALUE, &parmKey);
232 if (code != ERROR_SUCCESS)
235 dummyLen = sizeof(doTrace);
236 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
238 (BYTE *) &doTrace, &dummyLen);
239 RegCloseKey (parmKey);
240 if (code != ERROR_SUCCESS)
243 afsd_ForceTrace(FALSE);
246 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
247 ServiceStatus.dwWin32ExitCode = NO_ERROR;
248 ServiceStatus.dwCheckPoint = 1;
249 ServiceStatus.dwWaitHint = 10000;
250 ServiceStatus.dwControlsAccepted = 0;
251 SetServiceStatus(StatusHandle, &ServiceStatus);
252 SetEvent(WaitToTerminate);
256 case SERVICE_CONTROL_INTERROGATE:
257 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
258 ServiceStatus.dwWin32ExitCode = NO_ERROR;
259 ServiceStatus.dwCheckPoint = 0;
260 ServiceStatus.dwWaitHint = 0;
261 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
262 SetServiceStatus(StatusHandle, &ServiceStatus);
266 /* XXX handle system shutdown */
267 /* XXX handle pause & continue */
268 case SERVICE_CONTROL_POWEREVENT:
271 ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
272 ** Return NO_ERROR == return TRUE for that message, i.e. accept request
273 ** Return any error code to deny request,
274 ** i.e. as if returning BROADCAST_QUERY_DENY
276 if(powerEventsRegsitered) {
277 switch((int) dwEventType)
279 case PBT_APMQUERYSUSPEND:
280 case PBT_APMQUERYSTANDBY:
284 dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);
290 /* allow remaining case PBT_WhatEver */
293 case PBT_APMRESUMECRITICAL:
294 case PBT_APMRESUMESUSPEND:
295 case PBT_APMRESUMESTANDBY:
296 case PBT_APMBATTERYLOW:
297 case PBT_APMPOWERSTATUSCHANGE:
298 case PBT_APMOEMEVENT:
299 case PBT_APMRESUMEAUTOMATIC:
304 } /* end switch(ctrlCode) */
308 /* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
310 * Mount a drive into AFS if there global mapping
312 /* DEE Could check first if we are run as SYSTEM */
313 #define MAX_RETRIES 30
314 static void MountGlobalDrives()
316 char szAfsPath[_MAX_PATH];
317 char szDriveToMapTo[5];
321 DWORD dwIndex = 0, dwRetry = 0;
323 DWORD dwSubMountSize;
324 char szSubMount[256];
327 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
329 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
330 if (dwResult != ERROR_SUCCESS)
333 while (dwRetry < MAX_RETRIES) {
334 dwDriveSize = sizeof(szDriveToMapTo);
335 dwSubMountSize = sizeof(szSubMount);
336 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
337 if (dwResult != ERROR_MORE_DATA) {
338 if (dwResult != ERROR_SUCCESS) {
339 if (dwResult != ERROR_NO_MORE_ITEMS)
340 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
345 for ( ; dwRetry < MAX_RETRIES; dwRetry++)
348 memset (&nr, 0x00, sizeof(NETRESOURCE));
350 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
352 nr.dwScope = RESOURCE_GLOBALNET; /* ignored parameter */
353 nr.dwType=RESOURCETYPE_DISK;
354 nr.lpLocalName=szDriveToMapTo;
355 nr.lpRemoteName=szAfsPath;
356 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; /* ignored parameter */
357 nr.dwUsage = RESOURCEUSAGE_CONNECTABLE; /* ignored parameter */
359 dwResult = WNetAddConnection2(&nr,NULL,NULL,0);
360 afsi_log("GlobalAutoMap of %s to %s %s (%d)", szDriveToMapTo, szSubMount,
361 (dwResult == NO_ERROR) ? "succeeded" : "failed", dwResult);
362 if (dwResult == NO_ERROR) {
365 /* wait for smb server to come up */
366 Sleep((DWORD)1000 /* miliseconds */);
368 /* Disconnect any previous mappings */
369 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
376 static void DismountGlobalDrives()
378 char szAfsPath[_MAX_PATH];
379 char szDriveToMapTo[5];
385 DWORD dwSubMountSize;
386 char szSubMount[256];
389 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
391 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
392 if (dwResult != ERROR_SUCCESS)
396 dwDriveSize = sizeof(szDriveToMapTo);
397 dwSubMountSize = sizeof(szSubMount);
398 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
399 if (dwResult != ERROR_MORE_DATA) {
400 if (dwResult != ERROR_SUCCESS) {
401 if (dwResult != ERROR_NO_MORE_ITEMS)
402 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
407 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
409 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
410 dwResult = WNetCancelConnection(szAfsPath, TRUE);
412 afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
418 typedef BOOL ( APIENTRY * AfsdInitHook )(void);
419 #define AFSD_INIT_HOOK "AfsdInitHook"
420 #define AFSD_HOOK_DLL "afsdhook.dll"
423 control serviceex exists only on 2000/xp. These functions will be loaded dynamically.
426 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerExFunc )( LPCTSTR , LPHANDLER_FUNCTION_EX , LPVOID );
427 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerFunc )( LPCTSTR , LPHANDLER_FUNCTION );
429 RegisterServiceCtrlHandlerExFunc pRegisterServiceCtrlHandlerEx = NULL;
430 RegisterServiceCtrlHandlerFunc pRegisterServiceCtrlHandler = NULL;
432 void afsd_Main(DWORD argc, LPTSTR *argv)
441 AfsdInitHook initHook;
444 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
445 _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
448 osi_InitPanic(afsd_notifier);
449 osi_InitTraceOption();
455 WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
456 if ( GetLastError() == ERROR_ALREADY_EXISTS )
457 afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
460 hAdvApi32 = LoadLibrary("advapi32.dll");
461 if (hAdvApi32 == NULL)
463 afsi_log("Fatal: cannot load advapi32.dll");
467 pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA");
468 if (pRegisterServiceCtrlHandlerEx)
470 afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx");
471 StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL );
475 StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
478 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
479 ServiceStatus.dwServiceSpecificExitCode = 0;
480 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
481 ServiceStatus.dwWin32ExitCode = NO_ERROR;
482 ServiceStatus.dwCheckPoint = 1;
483 ServiceStatus.dwWaitHint = 30000;
484 /* accept Power Events */
485 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
486 SetServiceStatus(StatusHandle, &ServiceStatus);
490 HANDLE h; char *ptbuf[1];
491 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
492 ptbuf[0] = "AFS start pending";
493 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
494 DeregisterEventSource(h);
497 #ifdef REGISTER_POWER_NOTIFICATIONS
504 /* see if we should handle power notifications */
505 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0, KEY_QUERY_VALUE, &hkParm);
506 if(code == ERROR_SUCCESS) {
507 dummyLen = sizeof(bpower);
508 code = RegQueryValueEx(hkParm, "FlushOnHibernate", NULL, NULL,
509 (BYTE *) &bpower, &dummyLen);
511 if(code != ERROR_SUCCESS)
516 /* create thread used to flush cache */
518 PowerNotificationThreadCreate();
519 powerEventsRegsitered = 1;
524 /* allow an exit to be called prior to any initialization */
525 hInitHookDll = LoadLibrary(AFSD_HOOK_DLL);
529 initHook = ( AfsdInitHook ) GetProcAddress(hInitHookDll, AFSD_INIT_HOOK);
534 FreeLibrary(hInitHookDll);
539 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
540 ServiceStatus.dwWin32ExitCode = NO_ERROR;
541 ServiceStatus.dwCheckPoint = 0;
542 ServiceStatus.dwWaitHint = 0;
543 ServiceStatus.dwControlsAccepted = 0;
544 SetServiceStatus(StatusHandle, &ServiceStatus);
546 /* exit if initialization failed */
551 /* allow another 15 seconds to start */
552 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
553 ServiceStatus.dwServiceSpecificExitCode = 0;
554 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
555 ServiceStatus.dwWin32ExitCode = NO_ERROR;
556 ServiceStatus.dwCheckPoint = 2;
557 ServiceStatus.dwWaitHint = 20000;
558 /* accept Power Events */
559 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
560 SetServiceStatus(StatusHandle, &ServiceStatus);
565 MainThreadId = GetCurrentThreadId();
566 jmpret = setjmp(notifier_jmp);
571 code = afsd_InitCM(&reason);
573 afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
574 osi_panic(reason, __FILE__, __LINE__);
578 ServiceStatus.dwCheckPoint++;
579 ServiceStatus.dwWaitHint -= 5000;
580 SetServiceStatus(StatusHandle, &ServiceStatus);
582 code = afsd_InitDaemons(&reason);
584 afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
585 osi_panic(reason, __FILE__, __LINE__);
589 ServiceStatus.dwCheckPoint++;
590 ServiceStatus.dwWaitHint -= 5000;
591 SetServiceStatus(StatusHandle, &ServiceStatus);
593 code = afsd_InitSMB(&reason, MessageBox);
595 afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
596 osi_panic(reason, __FILE__, __LINE__);
602 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
603 ServiceStatus.dwWin32ExitCode = NO_ERROR;
604 ServiceStatus.dwCheckPoint = 0;
605 ServiceStatus.dwWaitHint = 0;
607 /* accept Power events */
608 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
609 SetServiceStatus(StatusHandle, &ServiceStatus);
612 HANDLE h; char *ptbuf[1];
613 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
614 ptbuf[0] = "AFS running";
615 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
616 DeregisterEventSource(h);
620 WaitForSingleObject(WaitToTerminate, INFINITE);
623 HANDLE h; char *ptbuf[1];
624 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
625 ptbuf[0] = "AFS quitting";
626 ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
627 0, 0, NULL, 1, 0, ptbuf, NULL);
628 DeregisterEventSource(h);
631 DismountGlobalDrives();
635 #ifdef REGISTER_POWER_NOTIFICATIONS
636 /* terminate thread used to flush cache */
637 if(powerEventsRegsitered)
638 PowerNotificationThreadExit();
641 /* Remove the ExceptionFilter */
642 SetUnhandledExceptionFilter(NULL);
644 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
645 ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
646 ServiceStatus.dwCheckPoint = 0;
647 ServiceStatus.dwWaitHint = 0;
648 ServiceStatus.dwControlsAccepted = 0;
649 SetServiceStatus(StatusHandle, &ServiceStatus);
652 DWORD __stdcall afsdMain_thread(void* notUsed)
654 char * argv[2] = {AFS_DAEMON_SERVICE_NAME, NULL};
655 afsd_Main(1, (LPTSTR*)argv);
662 static SERVICE_TABLE_ENTRY dispatchTable[] = {
663 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
667 if (!StartServiceCtrlDispatcher(dispatchTable))
669 LONG status = GetLastError();
670 if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
673 hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
675 printf("Hit <Enter> to terminate OpenAFS Client Service\n");
677 SetEvent(WaitToTerminate);
681 if ( hAFSDMainThread ) {
682 WaitForSingleObject( hAFSDMainThread, INFINITE );
683 CloseHandle( hAFSDMainThread );