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 WaitToTerminate;
48 unsigned int MainThreadId;
52 extern int traceOnPanic;
53 extern HANDLE afsi_file;
56 * Notifier function for use by osi_panic
58 static void afsd_notifier(char *msgp, char *filep, long line)
65 sprintf(tbuffer, "Error at file %s, line %d: %s",
68 sprintf(tbuffer, "Error at unknown location: %s", msgp);
70 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
72 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL);
73 DeregisterEventSource(h);
77 osi_LogEnable(afsd_logp);
79 afsd_ForceTrace(TRUE);
81 afsi_log("--- begin dump ---");
82 cm_DumpSCache(afsi_file, "a");
84 cm_dnlcDump(afsi_file, "a");
86 cm_DumpBufHashTable(afsi_file, "a");
87 smb_DumpVCP(afsi_file, "a");
88 afsi_log("--- end dump ---");
92 SetEvent(WaitToTerminate);
95 if (GetCurrentThreadId() == MainThreadId)
96 longjmp(notifier_jmp, 1);
103 * For use miscellaneously in smb.c; need to do better
105 static int DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
110 static SERVICE_STATUS ServiceStatus;
111 static SERVICE_STATUS_HANDLE StatusHandle;
114 afsd_ServiceFlushVolume(DWORD dwlpEventData)
116 DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
119 ** If UI bit is not set, user interaction is not possible
120 ** BUT, since we are a NON-interactive service, and therefore
121 ** have NO user I/O, it doesn't much matter.
122 ** This benign code left here as example of how to find this out
124 BOOL bUI = (dwlpEventData & 1);
127 if ( PowerNotificationThreadNotify() )
134 /* flush was unsuccessful, or timeout - deny shutdown */
135 dwRet = ERROR_NETWORK_BUSY;
138 /* to deny hibernate, simply return
139 // any value besides NO_ERROR.
141 // dwRet = ERROR_NETWORK_BUSY;
148 ** Extended ServiceControlHandler that provides Event types
149 ** for monitoring Power events, for example.
152 afsd_ServiceControlHandlerEx(
160 DWORD dummyLen, doTrace;
162 DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
166 case SERVICE_CONTROL_STOP:
168 RpcMgmtStopServerListening(NULL);
170 /* Force trace if requested */
171 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
173 0, KEY_QUERY_VALUE, &parmKey);
174 if (code != ERROR_SUCCESS)
177 dummyLen = sizeof(doTrace);
178 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
180 (BYTE *) &doTrace, &dummyLen);
181 RegCloseKey (parmKey);
182 if (code != ERROR_SUCCESS)
185 afsd_ForceTrace(FALSE);
188 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
189 ServiceStatus.dwWin32ExitCode = NO_ERROR;
190 ServiceStatus.dwCheckPoint = 1;
191 ServiceStatus.dwWaitHint = 10000;
192 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
193 SetServiceStatus(StatusHandle, &ServiceStatus);
194 SetEvent(WaitToTerminate);
198 case SERVICE_CONTROL_INTERROGATE:
199 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
200 ServiceStatus.dwWin32ExitCode = NO_ERROR;
201 ServiceStatus.dwCheckPoint = 0;
202 ServiceStatus.dwWaitHint = 0;
203 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
204 SetServiceStatus(StatusHandle, &ServiceStatus);
208 /* XXX handle system shutdown */
209 /* XXX handle pause & continue */
210 case SERVICE_CONTROL_POWEREVENT:
213 ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
214 ** Return NO_ERROR == return TRUE for that message, i.e. accept request
215 ** Return any error code to deny request,
216 ** i.e. as if returning BROADCAST_QUERY_DENY
218 switch((int) dwEventType)
220 case PBT_APMQUERYSUSPEND:
221 case PBT_APMQUERYSTANDBY:
223 #ifdef REGISTER_POWER_NOTIFICATIONS
225 dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);
231 /* allow remaining case PBT_WhatEver */
234 case PBT_APMRESUMECRITICAL:
235 case PBT_APMRESUMESUSPEND:
236 case PBT_APMRESUMESTANDBY:
237 case PBT_APMBATTERYLOW:
238 case PBT_APMPOWERSTATUSCHANGE:
239 case PBT_APMOEMEVENT:
240 case PBT_APMRESUMEAUTOMATIC:
245 } /* end switch(ctrlCode) */
250 /* This code was moved to Drivemap.cpp*/
251 /* Mount a drive into AFS if the user wants us to */
252 /* DEE Could check first if we are run as SYSTEM */
253 void CheckMountDrive()
255 char szAfsPath[_MAX_PATH];
256 char szDriveToMapTo[5];
262 DWORD dwSubMountSize;
263 char szSubMount[256];
266 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
268 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
269 if (dwResult != ERROR_SUCCESS)
273 dwDriveSize = sizeof(szDriveToMapTo);
274 dwSubMountSize = sizeof(szSubMount);
275 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
276 if (dwResult != ERROR_MORE_DATA) {
277 if (dwResult != ERROR_SUCCESS) {
278 if (dwResult != ERROR_NO_MORE_ITEMS)
279 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
285 sprintf(szAfsPath, "\\Device\\LanmanRedirector\\%s\\%s-AFS\\%s", szDriveToMapTo, cm_HostName, szSubMount);
287 dwResult = DefineDosDevice(DDD_RAW_TARGET_PATH, szDriveToMapTo, szAfsPath);
291 memset (&nr, 0x00, sizeof(NETRESOURCE));
293 sprintf(szAfsPath,"\\\\%s-AFS\\%s",cm_HostName,szSubMount);
295 nr.dwScope = RESOURCE_GLOBALNET;
296 nr.dwType=RESOURCETYPE_DISK;
297 nr.lpLocalName=szDriveToMapTo;
298 nr.lpRemoteName=szAfsPath;
299 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
300 nr.dwUsage = RESOURCEUSAGE_CONNECTABLE;
302 dwResult = WNetAddConnection2(&nr,NULL,NULL,FALSE);
305 afsi_log("GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
312 typedef BOOL ( APIENTRY * AfsdInitHook )(void);
313 #define AFSD_INIT_HOOK "AfsdInitHook"
314 #define AFSD_HOOK_DLL "afsdhook.dll"
316 void afsd_Main(DWORD argc, LPTSTR *argv)
322 AfsdInitHook initHook;
325 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
326 _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
329 osi_InitPanic(afsd_notifier);
330 osi_InitTraceOption();
334 WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
335 if ( GetLastError() == ERROR_ALREADY_EXISTS )
336 afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
339 StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME,
340 (LPHANDLER_FUNCTION_EX) afsd_ServiceControlHandlerEx,
341 NULL /* user context */
344 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
345 ServiceStatus.dwServiceSpecificExitCode = 0;
346 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
347 ServiceStatus.dwWin32ExitCode = NO_ERROR;
348 ServiceStatus.dwCheckPoint = 1;
349 ServiceStatus.dwWaitHint = 30000;
350 /* accept Power Events */
351 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
352 SetServiceStatus(StatusHandle, &ServiceStatus);
356 HANDLE h; char *ptbuf[1];
357 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
358 ptbuf[0] = "AFS start pending";
359 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
360 DeregisterEventSource(h);
363 #ifdef REGISTER_POWER_NOTIFICATIONS
364 /* create thread used to flush cache */
365 PowerNotificationThreadCreate();
370 /* allow an exit to be called prior to any initialization */
371 hInitHookDll = LoadLibrary(AFSD_HOOK_DLL);
375 initHook = ( AfsdInitHook ) GetProcAddress(hInitHookDll, AFSD_INIT_HOOK);
380 FreeLibrary(hInitHookDll);
384 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
385 ServiceStatus.dwWin32ExitCode = NO_ERROR;
386 ServiceStatus.dwCheckPoint = 0;
387 ServiceStatus.dwWaitHint = 0;
388 ServiceStatus.dwControlsAccepted = 0;
389 SetServiceStatus(StatusHandle, &ServiceStatus);
391 /* exit if initialization failed */
396 /* allow another 15 seconds to start */
397 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
398 ServiceStatus.dwServiceSpecificExitCode = 0;
399 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
400 ServiceStatus.dwWin32ExitCode = NO_ERROR;
401 ServiceStatus.dwCheckPoint = 2;
402 ServiceStatus.dwWaitHint = 20000;
403 /* accept Power Events */
404 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
405 SetServiceStatus(StatusHandle, &ServiceStatus);
410 MainThreadId = GetCurrentThreadId();
411 jmpret = setjmp(notifier_jmp);
416 code = afsd_InitCM(&reason);
418 osi_panic(reason, __FILE__, __LINE__);
421 ServiceStatus.dwCheckPoint++;
422 ServiceStatus.dwWaitHint -= 5000;
423 SetServiceStatus(StatusHandle, &ServiceStatus);
425 code = afsd_InitDaemons(&reason);
427 osi_panic(reason, __FILE__, __LINE__);
430 ServiceStatus.dwCheckPoint++;
431 ServiceStatus.dwWaitHint -= 5000;
432 SetServiceStatus(StatusHandle, &ServiceStatus);
434 code = afsd_InitSMB(&reason, DummyMessageBox);
436 osi_panic(reason, __FILE__, __LINE__);
439 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
440 ServiceStatus.dwWin32ExitCode = NO_ERROR;
441 ServiceStatus.dwCheckPoint = 0;
442 ServiceStatus.dwWaitHint = 0;
444 /* accept Power events */
445 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
446 SetServiceStatus(StatusHandle, &ServiceStatus);
449 HANDLE h; char *ptbuf[1];
450 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
451 ptbuf[0] = "AFS running";
452 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
453 DeregisterEventSource(h);
457 /* Check if we should mount a drive into AFS */
460 WaitForSingleObject(WaitToTerminate, INFINITE);
462 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
463 ServiceStatus.dwWin32ExitCode = NO_ERROR;
464 ServiceStatus.dwCheckPoint = 0;
465 ServiceStatus.dwWaitHint = 5000;
466 ServiceStatus.dwControlsAccepted = 0;
467 SetServiceStatus(StatusHandle, &ServiceStatus);
470 HANDLE h; char *ptbuf[1];
471 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
472 ptbuf[0] = "AFS quitting";
473 ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
474 0, 0, NULL, 1, 0, ptbuf, NULL);
475 DeregisterEventSource(h);
478 #ifdef REGISTER_POWER_NOTIFICATIONS
479 /* terminate thread used to flush cache */
480 PowerNotificationThreadExit();
483 /* Remove the ExceptionFilter */
484 SetUnhandledExceptionFilter(NULL);
486 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
487 ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
488 ServiceStatus.dwCheckPoint = 0;
489 ServiceStatus.dwWaitHint = 0;
490 ServiceStatus.dwControlsAccepted = 0;
491 SetServiceStatus(StatusHandle, &ServiceStatus);
495 DWORD __stdcall afsdMain_thread(void* notUsed)
497 afsd_Main(0, (LPTSTR*)NULL);
503 SERVICE_TABLE_ENTRY dispatchTable[] = {
504 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
508 afsd_SetUnhandledExceptionFilter();
510 if (!StartServiceCtrlDispatcher(dispatchTable))
512 LONG status = GetLastError();
513 if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
516 CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
518 printf("Hit <Enter> to terminate OpenAFS Client Service\n");
520 SetEvent(WaitToTerminate);