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;
59 * Notifier function for use by osi_panic
61 static void afsd_notifier(char *msgp, char *filep, long line)
68 sprintf(tbuffer, "Error at file %s, line %d: %s",
71 sprintf(tbuffer, "Error at unknown location: %s", msgp);
73 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
75 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL);
76 DeregisterEventSource(h);
80 osi_LogEnable(afsd_logp);
82 afsd_ForceTrace(TRUE);
84 afsi_log("--- begin dump ---");
85 cm_DumpSCache(afsi_file, "a");
87 cm_dnlcDump(afsi_file, "a");
89 cm_DumpBufHashTable(afsi_file, "a");
90 smb_DumpVCP(afsi_file, "a");
91 afsi_log("--- end dump ---");
95 SetEvent(WaitToTerminate);
98 if (GetCurrentThreadId() == MainThreadId)
99 longjmp(notifier_jmp, 1);
106 * For use miscellaneously in smb.c; need to do better
108 static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
113 static SERVICE_STATUS ServiceStatus;
114 static SERVICE_STATUS_HANDLE StatusHandle;
117 afsd_ServiceFlushVolume(DWORD dwlpEventData)
119 DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
122 ** If UI bit is not set, user interaction is not possible
123 ** BUT, since we are a NON-interactive service, and therefore
124 ** have NO user I/O, it doesn't much matter.
125 ** This benign code left here as example of how to find this out
127 BOOL bUI = (dwlpEventData & 1);
130 if ( PowerNotificationThreadNotify() )
136 /* flush was unsuccessful, or timeout - deny shutdown */
137 dwRet = ERROR_NETWORK_BUSY;
140 /* to deny hibernate, simply return
141 // any value besides NO_ERROR.
143 // dwRet = ERROR_NETWORK_BUSY;
150 /* service control handler used in nt4 only for backward compat. */
152 afsd_ServiceControlHandler(DWORD ctrlCode)
155 DWORD dummyLen, doTrace;
159 case SERVICE_CONTROL_STOP:
161 RpcMgmtStopServerListening(NULL);
163 /* Force trace if requested */
164 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
166 0, KEY_QUERY_VALUE, &parmKey);
167 if (code != ERROR_SUCCESS)
170 dummyLen = sizeof(doTrace);
171 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
173 (BYTE *) &doTrace, &dummyLen);
174 RegCloseKey (parmKey);
175 if (code != ERROR_SUCCESS)
178 afsd_ForceTrace(FALSE);
181 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
182 ServiceStatus.dwWin32ExitCode = NO_ERROR;
183 ServiceStatus.dwCheckPoint = 1;
184 ServiceStatus.dwWaitHint = 10000;
185 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
186 SetServiceStatus(StatusHandle, &ServiceStatus);
187 SetEvent(WaitToTerminate);
189 case SERVICE_CONTROL_INTERROGATE:
190 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
191 ServiceStatus.dwWin32ExitCode = NO_ERROR;
192 ServiceStatus.dwCheckPoint = 0;
193 ServiceStatus.dwWaitHint = 0;
194 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
195 SetServiceStatus(StatusHandle, &ServiceStatus);
197 /* XXX handle system shutdown */
198 /* XXX handle pause & continue */
204 ** Extended ServiceControlHandler that provides Event types
205 ** for monitoring Power events, for example.
208 afsd_ServiceControlHandlerEx(
216 DWORD dummyLen, doTrace;
218 DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
222 case SERVICE_CONTROL_STOP:
224 RpcMgmtStopServerListening(NULL);
226 /* Force trace if requested */
227 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
229 0, KEY_QUERY_VALUE, &parmKey);
230 if (code != ERROR_SUCCESS)
233 dummyLen = sizeof(doTrace);
234 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
236 (BYTE *) &doTrace, &dummyLen);
237 RegCloseKey (parmKey);
238 if (code != ERROR_SUCCESS)
241 afsd_ForceTrace(FALSE);
244 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
245 ServiceStatus.dwWin32ExitCode = NO_ERROR;
246 ServiceStatus.dwCheckPoint = 1;
247 ServiceStatus.dwWaitHint = 10000;
248 ServiceStatus.dwControlsAccepted = 0;
249 SetServiceStatus(StatusHandle, &ServiceStatus);
250 SetEvent(WaitToTerminate);
254 case SERVICE_CONTROL_INTERROGATE:
255 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
256 ServiceStatus.dwWin32ExitCode = NO_ERROR;
257 ServiceStatus.dwCheckPoint = 0;
258 ServiceStatus.dwWaitHint = 0;
259 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
260 SetServiceStatus(StatusHandle, &ServiceStatus);
264 /* XXX handle system shutdown */
265 /* XXX handle pause & continue */
266 case SERVICE_CONTROL_POWEREVENT:
269 ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
270 ** Return NO_ERROR == return TRUE for that message, i.e. accept request
271 ** Return any error code to deny request,
272 ** i.e. as if returning BROADCAST_QUERY_DENY
274 switch((int) dwEventType)
276 case PBT_APMQUERYSUSPEND:
277 case PBT_APMQUERYSTANDBY:
281 dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);
287 /* allow remaining case PBT_WhatEver */
290 case PBT_APMRESUMECRITICAL:
291 case PBT_APMRESUMESUSPEND:
292 case PBT_APMRESUMESTANDBY:
293 case PBT_APMBATTERYLOW:
294 case PBT_APMPOWERSTATUSCHANGE:
295 case PBT_APMOEMEVENT:
296 case PBT_APMRESUMEAUTOMATIC:
301 } /* end switch(ctrlCode) */
305 /* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
307 * Mount a drive into AFS if there global mapping
309 /* DEE Could check first if we are run as SYSTEM */
310 #define MAX_RETRIES 30
311 static void MountGlobalDrives()
313 char szAfsPath[_MAX_PATH];
314 char szDriveToMapTo[5];
318 DWORD dwIndex = 0, dwRetry = 0;
320 DWORD dwSubMountSize;
321 char szSubMount[256];
324 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
326 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
327 if (dwResult != ERROR_SUCCESS)
330 while (dwRetry < MAX_RETRIES) {
331 dwDriveSize = sizeof(szDriveToMapTo);
332 dwSubMountSize = sizeof(szSubMount);
333 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
334 if (dwResult != ERROR_MORE_DATA) {
335 if (dwResult != ERROR_SUCCESS) {
336 if (dwResult != ERROR_NO_MORE_ITEMS)
337 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
342 for ( ; dwRetry < MAX_RETRIES; dwRetry++)
345 memset (&nr, 0x00, sizeof(NETRESOURCE));
347 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
349 nr.dwScope = RESOURCE_GLOBALNET; /* ignored parameter */
350 nr.dwType=RESOURCETYPE_DISK;
351 nr.lpLocalName=szDriveToMapTo;
352 nr.lpRemoteName=szAfsPath;
353 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; /* ignored parameter */
354 nr.dwUsage = RESOURCEUSAGE_CONNECTABLE; /* ignored parameter */
356 dwResult = WNetAddConnection2(&nr,NULL,NULL,0);
357 afsi_log("GlobalAutoMap of %s to %s %s (%d)", szDriveToMapTo, szSubMount,
358 (dwResult == NO_ERROR) ? "succeeded" : "failed", dwResult);
359 if (dwResult == NO_ERROR) {
362 /* wait for smb server to come up */
363 Sleep((DWORD)1000 /* miliseconds */);
365 /* Disconnect any previous mappings */
366 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
373 static void DismountGlobalDrives()
375 char szAfsPath[_MAX_PATH];
376 char szDriveToMapTo[5];
382 DWORD dwSubMountSize;
383 char szSubMount[256];
386 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
388 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
389 if (dwResult != ERROR_SUCCESS)
393 dwDriveSize = sizeof(szDriveToMapTo);
394 dwSubMountSize = sizeof(szSubMount);
395 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
396 if (dwResult != ERROR_MORE_DATA) {
397 if (dwResult != ERROR_SUCCESS) {
398 if (dwResult != ERROR_NO_MORE_ITEMS)
399 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
404 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
406 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
407 dwResult = WNetCancelConnection(szAfsPath, TRUE);
409 afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
415 typedef BOOL ( APIENTRY * AfsdInitHook )(void);
416 #define AFSD_INIT_HOOK "AfsdInitHook"
417 #define AFSD_HOOK_DLL "afsdhook.dll"
420 control serviceex exists only on 2000/xp. These functions will be loaded dynamically.
423 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerExFunc )( LPCTSTR , LPHANDLER_FUNCTION_EX , LPVOID );
424 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerFunc )( LPCTSTR , LPHANDLER_FUNCTION );
426 RegisterServiceCtrlHandlerExFunc pRegisterServiceCtrlHandlerEx = NULL;
427 RegisterServiceCtrlHandlerFunc pRegisterServiceCtrlHandler = NULL;
429 void afsd_Main(DWORD argc, LPTSTR *argv)
438 AfsdInitHook initHook;
441 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
442 _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
445 osi_InitPanic(afsd_notifier);
446 osi_InitTraceOption();
452 WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
453 if ( GetLastError() == ERROR_ALREADY_EXISTS )
454 afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
457 hAdvApi32 = LoadLibrary("advapi32.dll");
458 if (hAdvApi32 == NULL)
460 afsi_log("Fatal: cannot load advapi32.dll");
464 pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA");
465 if (pRegisterServiceCtrlHandlerEx)
467 afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx");
468 StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL );
472 StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
475 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
476 ServiceStatus.dwServiceSpecificExitCode = 0;
477 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
478 ServiceStatus.dwWin32ExitCode = NO_ERROR;
479 ServiceStatus.dwCheckPoint = 1;
480 ServiceStatus.dwWaitHint = 30000;
481 /* accept Power Events */
482 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
483 SetServiceStatus(StatusHandle, &ServiceStatus);
487 HANDLE h; char *ptbuf[1];
488 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
489 ptbuf[0] = "AFS start pending";
490 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
491 DeregisterEventSource(h);
494 #ifdef REGISTER_POWER_NOTIFICATIONS
495 /* create thread used to flush cache */
496 PowerNotificationThreadCreate();
499 /* allow an exit to be called prior to any initialization */
500 hInitHookDll = LoadLibrary(AFSD_HOOK_DLL);
504 initHook = ( AfsdInitHook ) GetProcAddress(hInitHookDll, AFSD_INIT_HOOK);
509 FreeLibrary(hInitHookDll);
514 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
515 ServiceStatus.dwWin32ExitCode = NO_ERROR;
516 ServiceStatus.dwCheckPoint = 0;
517 ServiceStatus.dwWaitHint = 0;
518 ServiceStatus.dwControlsAccepted = 0;
519 SetServiceStatus(StatusHandle, &ServiceStatus);
521 /* exit if initialization failed */
526 /* allow another 15 seconds to start */
527 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
528 ServiceStatus.dwServiceSpecificExitCode = 0;
529 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
530 ServiceStatus.dwWin32ExitCode = NO_ERROR;
531 ServiceStatus.dwCheckPoint = 2;
532 ServiceStatus.dwWaitHint = 20000;
533 /* accept Power Events */
534 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
535 SetServiceStatus(StatusHandle, &ServiceStatus);
540 MainThreadId = GetCurrentThreadId();
541 jmpret = setjmp(notifier_jmp);
546 code = afsd_InitCM(&reason);
548 afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
549 osi_panic(reason, __FILE__, __LINE__);
553 ServiceStatus.dwCheckPoint++;
554 ServiceStatus.dwWaitHint -= 5000;
555 SetServiceStatus(StatusHandle, &ServiceStatus);
557 code = afsd_InitDaemons(&reason);
559 afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
560 osi_panic(reason, __FILE__, __LINE__);
564 ServiceStatus.dwCheckPoint++;
565 ServiceStatus.dwWaitHint -= 5000;
566 SetServiceStatus(StatusHandle, &ServiceStatus);
568 code = afsd_InitSMB(&reason, MessageBox);
570 afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
571 osi_panic(reason, __FILE__, __LINE__);
577 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
578 ServiceStatus.dwWin32ExitCode = NO_ERROR;
579 ServiceStatus.dwCheckPoint = 0;
580 ServiceStatus.dwWaitHint = 0;
582 /* accept Power events */
583 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
584 SetServiceStatus(StatusHandle, &ServiceStatus);
587 HANDLE h; char *ptbuf[1];
588 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
589 ptbuf[0] = "AFS running";
590 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
591 DeregisterEventSource(h);
595 WaitForSingleObject(WaitToTerminate, INFINITE);
598 HANDLE h; char *ptbuf[1];
599 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
600 ptbuf[0] = "AFS quitting";
601 ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
602 0, 0, NULL, 1, 0, ptbuf, NULL);
603 DeregisterEventSource(h);
606 DismountGlobalDrives();
610 #ifdef REGISTER_POWER_NOTIFICATIONS
611 /* terminate thread used to flush cache */
612 PowerNotificationThreadExit();
615 /* Remove the ExceptionFilter */
616 SetUnhandledExceptionFilter(NULL);
618 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
619 ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
620 ServiceStatus.dwCheckPoint = 0;
621 ServiceStatus.dwWaitHint = 0;
622 ServiceStatus.dwControlsAccepted = 0;
623 SetServiceStatus(StatusHandle, &ServiceStatus);
626 DWORD __stdcall afsdMain_thread(void* notUsed)
628 char * argv[2] = {AFS_DAEMON_SERVICE_NAME, NULL};
629 afsd_Main(1, (LPTSTR*)argv);
636 static SERVICE_TABLE_ENTRY dispatchTable[] = {
637 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
641 if (!StartServiceCtrlDispatcher(dispatchTable))
643 LONG status = GetLastError();
644 if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
647 hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
649 printf("Hit <Enter> to terminate OpenAFS Client Service\n");
651 SetEvent(WaitToTerminate);
655 if ( hAFSDMainThread ) {
656 WaitForSingleObject( hAFSDMainThread, INFINITE );
657 CloseHandle( hAFSDMainThread );