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
39 #include "afsd_flushvol.h"
41 extern void afsi_log(char *pattern, ...);
43 HANDLE hAFSDMainThread = NULL;
45 HANDLE WaitToTerminate;
50 unsigned int MainThreadId;
54 extern int traceOnPanic;
55 extern HANDLE afsi_file;
58 * Notifier function for use by osi_panic
60 static void afsd_notifier(char *msgp, char *filep, long line)
67 sprintf(tbuffer, "Error at file %s, line %d: %s",
70 sprintf(tbuffer, "Error at unknown location: %s", msgp);
72 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
74 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL);
75 DeregisterEventSource(h);
79 osi_LogEnable(afsd_logp);
81 afsd_ForceTrace(TRUE);
83 afsi_log("--- begin dump ---");
84 cm_DumpSCache(afsi_file, "a");
86 cm_dnlcDump(afsi_file, "a");
88 cm_DumpBufHashTable(afsi_file, "a");
89 smb_DumpVCP(afsi_file, "a");
90 afsi_log("--- end dump ---");
94 SetEvent(WaitToTerminate);
97 if (GetCurrentThreadId() == MainThreadId)
98 longjmp(notifier_jmp, 1);
105 * For use miscellaneously in smb.c; need to do better
107 static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
112 static SERVICE_STATUS ServiceStatus;
113 static SERVICE_STATUS_HANDLE StatusHandle;
116 afsd_ServiceFlushVolume(DWORD dwlpEventData)
118 DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
121 ** If UI bit is not set, user interaction is not possible
122 ** BUT, since we are a NON-interactive service, and therefore
123 ** have NO user I/O, it doesn't much matter.
124 ** This benign code left here as example of how to find this out
126 BOOL bUI = (dwlpEventData & 1);
129 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 ** Extended ServiceControlHandler that provides Event types
151 ** for monitoring Power events, for example.
154 afsd_ServiceControlHandlerEx(
162 DWORD dummyLen, doTrace;
164 DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
168 case SERVICE_CONTROL_STOP:
170 RpcMgmtStopServerListening(NULL);
172 /* Force trace if requested */
173 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
175 0, KEY_QUERY_VALUE, &parmKey);
176 if (code != ERROR_SUCCESS)
179 dummyLen = sizeof(doTrace);
180 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
182 (BYTE *) &doTrace, &dummyLen);
183 RegCloseKey (parmKey);
184 if (code != ERROR_SUCCESS)
187 afsd_ForceTrace(FALSE);
190 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
191 ServiceStatus.dwWin32ExitCode = NO_ERROR;
192 ServiceStatus.dwCheckPoint = 1;
193 ServiceStatus.dwWaitHint = 10000;
194 ServiceStatus.dwControlsAccepted = 0;
195 SetServiceStatus(StatusHandle, &ServiceStatus);
196 SetEvent(WaitToTerminate);
200 case SERVICE_CONTROL_INTERROGATE:
201 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
202 ServiceStatus.dwWin32ExitCode = NO_ERROR;
203 ServiceStatus.dwCheckPoint = 0;
204 ServiceStatus.dwWaitHint = 0;
205 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
206 SetServiceStatus(StatusHandle, &ServiceStatus);
210 /* XXX handle system shutdown */
211 /* XXX handle pause & continue */
212 case SERVICE_CONTROL_POWEREVENT:
215 ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
216 ** Return NO_ERROR == return TRUE for that message, i.e. accept request
217 ** Return any error code to deny request,
218 ** i.e. as if returning BROADCAST_QUERY_DENY
220 switch((int) dwEventType)
222 case PBT_APMQUERYSUSPEND:
223 case PBT_APMQUERYSTANDBY:
225 #ifdef REGISTER_POWER_NOTIFICATIONS
227 dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);
233 /* allow remaining case PBT_WhatEver */
236 case PBT_APMRESUMECRITICAL:
237 case PBT_APMRESUMESUSPEND:
238 case PBT_APMRESUMESTANDBY:
239 case PBT_APMBATTERYLOW:
240 case PBT_APMPOWERSTATUSCHANGE:
241 case PBT_APMOEMEVENT:
242 case PBT_APMRESUMEAUTOMATIC:
247 } /* end switch(ctrlCode) */
251 /* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
253 * Mount a drive into AFS if there global mapping
255 /* DEE Could check first if we are run as SYSTEM */
256 static void MountGlobalDrives()
258 char szAfsPath[_MAX_PATH];
259 char szDriveToMapTo[5];
265 DWORD dwSubMountSize;
266 char szSubMount[256];
269 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
271 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
272 if (dwResult != ERROR_SUCCESS)
276 dwDriveSize = sizeof(szDriveToMapTo);
277 dwSubMountSize = sizeof(szSubMount);
278 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
279 if (dwResult != ERROR_MORE_DATA) {
280 if (dwResult != ERROR_SUCCESS) {
281 if (dwResult != ERROR_NO_MORE_ITEMS)
282 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
289 memset (&nr, 0x00, sizeof(NETRESOURCE));
291 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
293 nr.dwScope = RESOURCE_GLOBALNET;
294 nr.dwType=RESOURCETYPE_DISK;
295 nr.lpLocalName=szDriveToMapTo;
296 nr.lpRemoteName=szAfsPath;
297 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
298 nr.dwUsage = RESOURCEUSAGE_CONNECTABLE;
300 dwResult = WNetAddConnection2(&nr,NULL,NULL,FALSE);
302 afsi_log("GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
308 static void DismountGlobalDrives()
310 char szAfsPath[_MAX_PATH];
311 char szDriveToMapTo[5];
317 DWORD dwSubMountSize;
318 char szSubMount[256];
321 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
323 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
324 if (dwResult != ERROR_SUCCESS)
328 dwDriveSize = sizeof(szDriveToMapTo);
329 dwSubMountSize = sizeof(szSubMount);
330 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
331 if (dwResult != ERROR_MORE_DATA) {
332 if (dwResult != ERROR_SUCCESS) {
333 if (dwResult != ERROR_NO_MORE_ITEMS)
334 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
339 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
341 dwResult = WNetCancelConnection(szAfsPath, TRUE);
343 afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
349 typedef BOOL ( APIENTRY * AfsdInitHook )(void);
350 #define AFSD_INIT_HOOK "AfsdInitHook"
351 #define AFSD_HOOK_DLL "afsdhook.dll"
353 void afsd_Main(DWORD argc, LPTSTR *argv)
361 AfsdInitHook initHook;
364 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
365 _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
368 osi_InitPanic(afsd_notifier);
369 osi_InitTraceOption();
375 WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
376 if ( GetLastError() == ERROR_ALREADY_EXISTS )
377 afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
380 StatusHandle = RegisterServiceCtrlHandlerEx(argv[0] /* AFS_DAEMON_SERVICE_NAME */,
381 (LPHANDLER_FUNCTION_EX) afsd_ServiceControlHandlerEx,
382 NULL /* user context */
385 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
386 ServiceStatus.dwServiceSpecificExitCode = 0;
387 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
388 ServiceStatus.dwWin32ExitCode = NO_ERROR;
389 ServiceStatus.dwCheckPoint = 1;
390 ServiceStatus.dwWaitHint = 30000;
391 /* accept Power Events */
392 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
393 SetServiceStatus(StatusHandle, &ServiceStatus);
397 HANDLE h; char *ptbuf[1];
398 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
399 ptbuf[0] = "AFS start pending";
400 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
401 DeregisterEventSource(h);
404 #ifdef REGISTER_POWER_NOTIFICATIONS
405 /* create thread used to flush cache */
406 PowerNotificationThreadCreate();
409 /* allow an exit to be called prior to any initialization */
410 hInitHookDll = LoadLibrary(AFSD_HOOK_DLL);
414 initHook = ( AfsdInitHook ) GetProcAddress(hInitHookDll, AFSD_INIT_HOOK);
419 FreeLibrary(hInitHookDll);
423 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
424 ServiceStatus.dwWin32ExitCode = NO_ERROR;
425 ServiceStatus.dwCheckPoint = 0;
426 ServiceStatus.dwWaitHint = 0;
427 ServiceStatus.dwControlsAccepted = 0;
428 SetServiceStatus(StatusHandle, &ServiceStatus);
430 /* exit if initialization failed */
435 /* allow another 15 seconds to start */
436 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
437 ServiceStatus.dwServiceSpecificExitCode = 0;
438 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
439 ServiceStatus.dwWin32ExitCode = NO_ERROR;
440 ServiceStatus.dwCheckPoint = 2;
441 ServiceStatus.dwWaitHint = 20000;
442 /* accept Power Events */
443 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
444 SetServiceStatus(StatusHandle, &ServiceStatus);
449 MainThreadId = GetCurrentThreadId();
450 jmpret = setjmp(notifier_jmp);
455 code = afsd_InitCM(&reason);
457 afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
458 osi_panic(reason, __FILE__, __LINE__);
462 ServiceStatus.dwCheckPoint++;
463 ServiceStatus.dwWaitHint -= 5000;
464 SetServiceStatus(StatusHandle, &ServiceStatus);
466 code = afsd_InitDaemons(&reason);
468 afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
469 osi_panic(reason, __FILE__, __LINE__);
473 ServiceStatus.dwCheckPoint++;
474 ServiceStatus.dwWaitHint -= 5000;
475 SetServiceStatus(StatusHandle, &ServiceStatus);
477 code = afsd_InitSMB(&reason, MessageBox);
479 afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
480 osi_panic(reason, __FILE__, __LINE__);
486 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
487 ServiceStatus.dwWin32ExitCode = NO_ERROR;
488 ServiceStatus.dwCheckPoint = 0;
489 ServiceStatus.dwWaitHint = 0;
491 /* accept Power events */
492 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
493 SetServiceStatus(StatusHandle, &ServiceStatus);
496 HANDLE h; char *ptbuf[1];
497 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
498 ptbuf[0] = "AFS running";
499 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
500 DeregisterEventSource(h);
504 WaitForSingleObject(WaitToTerminate, INFINITE);
507 HANDLE h; char *ptbuf[1];
508 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
509 ptbuf[0] = "AFS quitting";
510 ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
511 0, 0, NULL, 1, 0, ptbuf, NULL);
512 DeregisterEventSource(h);
515 DismountGlobalDrives();
519 #ifdef REGISTER_POWER_NOTIFICATIONS
520 /* terminate thread used to flush cache */
521 PowerNotificationThreadExit();
524 /* Remove the ExceptionFilter */
525 SetUnhandledExceptionFilter(NULL);
528 FreeLibrary(hInitHookDll);
532 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
533 ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
534 ServiceStatus.dwCheckPoint = 0;
535 ServiceStatus.dwWaitHint = 0;
536 ServiceStatus.dwControlsAccepted = 0;
537 SetServiceStatus(StatusHandle, &ServiceStatus);
541 DWORD __stdcall afsdMain_thread(void* notUsed)
543 char * argv[2] = {AFS_DAEMON_SERVICE_NAME, NULL};
544 afsd_Main(1, (LPTSTR*)argv);
551 static SERVICE_TABLE_ENTRY dispatchTable[] = {
552 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
556 if (!StartServiceCtrlDispatcher(dispatchTable))
558 LONG status = GetLastError();
559 if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
562 hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
564 printf("Hit <Enter> to terminate OpenAFS Client Service\n");
566 SetEvent(WaitToTerminate);
570 if ( hAFSDMainThread ) {
571 WaitForSingleObject( hAFSDMainThread, INFINITE );
572 CloseHandle( hAFSDMainThread );