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;
47 unsigned int MainThreadId;
50 extern int traceOnPanic;
51 extern HANDLE afsi_file;
54 * Notifier function for use by osi_panic
56 static void afsd_notifier(char *msgp, char *filep, long line)
63 sprintf(tbuffer, "Error at file %s, line %d: %s",
66 sprintf(tbuffer, "Error at unknown location: %s", msgp);
68 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
70 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL);
71 DeregisterEventSource(h);
75 osi_LogEnable(afsd_logp);
77 afsd_ForceTrace(TRUE);
79 afsi_log("--- begin dump ---");
80 cm_DumpSCache(afsi_file, "a");
82 cm_dnlcDump(afsi_file, "a");
84 cm_DumpBufHashTable(afsi_file, "a");
85 smb_DumpVCP(afsi_file, "a");
86 afsi_log("--- end dump ---");
90 SetEvent(WaitToTerminate);
92 if (GetCurrentThreadId() == MainThreadId)
93 longjmp(notifier_jmp, 1);
99 * For use miscellaneously in smb.c; need to do better
101 static int DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
106 static SERVICE_STATUS ServiceStatus;
107 static SERVICE_STATUS_HANDLE StatusHandle;
110 afsd_ServiceFlushVolume(DWORD dwlpEventData)
112 DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
115 ** If UI bit is not set, user interaction is not possible
116 ** BUT, since we are a NON-interactive service, and therefore
117 ** have NO user I/O, it doesn't much matter.
118 ** This benign code left here as example of how to find this out
120 BOOL bUI = (dwlpEventData & 1);
123 if ( PowerNotificationThreadNotify() )
130 /* flush was unsuccessful, or timeout - deny shutdown */
131 dwRet = ERROR_NETWORK_BUSY;
134 /* to deny hibernate, simply return
135 // any value besides NO_ERROR.
137 // dwRet = ERROR_NETWORK_BUSY;
144 ** Extended ServiceControlHandler that provides Event types
145 ** for monitoring Power events, for example.
148 afsd_ServiceControlHandlerEx(
156 DWORD dummyLen, doTrace;
158 DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
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);
184 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
185 ServiceStatus.dwWin32ExitCode = NO_ERROR;
186 ServiceStatus.dwCheckPoint = 1;
187 ServiceStatus.dwWaitHint = 10000;
188 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
189 SetServiceStatus(StatusHandle, &ServiceStatus);
190 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 | SERVICE_ACCEPT_POWEREVENT;
200 SetServiceStatus(StatusHandle, &ServiceStatus);
204 /* XXX handle system shutdown */
205 /* XXX handle pause & continue */
206 case SERVICE_CONTROL_POWEREVENT:
209 ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
210 ** Return NO_ERROR == return TRUE for that message, i.e. accept request
211 ** Return any error code to deny request,
212 ** i.e. as if returning BROADCAST_QUERY_DENY
214 switch((int) dwEventType)
216 case PBT_APMQUERYSUSPEND:
217 case PBT_APMQUERYSTANDBY:
219 #ifdef REGISTER_POWER_NOTIFICATIONS
221 dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);
227 /* allow remaining case PBT_WhatEver */
230 case PBT_APMRESUMECRITICAL:
231 case PBT_APMRESUMESUSPEND:
232 case PBT_APMRESUMESTANDBY:
233 case PBT_APMBATTERYLOW:
234 case PBT_APMPOWERSTATUSCHANGE:
235 case PBT_APMOEMEVENT:
236 case PBT_APMRESUMEAUTOMATIC:
241 } /* end switch(ctrlCode) */
246 /* This code was moved to Drivemap.cpp*/
247 /* Mount a drive into AFS if the user wants us to */
248 /* DEE Could check first if we are run as SYSTEM */
249 void CheckMountDrive()
251 char szAfsPath[_MAX_PATH];
252 char szDriveToMapTo[5];
258 DWORD dwSubMountSize;
259 char szSubMount[256];
262 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
264 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
265 if (dwResult != ERROR_SUCCESS)
269 dwDriveSize = sizeof(szDriveToMapTo);
270 dwSubMountSize = sizeof(szSubMount);
271 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
272 if (dwResult != ERROR_MORE_DATA) {
273 if (dwResult != ERROR_SUCCESS) {
274 if (dwResult != ERROR_NO_MORE_ITEMS)
275 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
281 sprintf(szAfsPath, "\\Device\\LanmanRedirector\\%s\\%s-AFS\\%s", szDriveToMapTo, cm_HostName, szSubMount);
283 dwResult = DefineDosDevice(DDD_RAW_TARGET_PATH, szDriveToMapTo, szAfsPath);
287 memset (&nr, 0x00, sizeof(NETRESOURCE));
289 sprintf(szAfsPath,"\\\\%s-AFS\\%s",cm_HostName,szSubMount);
291 nr.dwScope = RESOURCE_GLOBALNET;
292 nr.dwType=RESOURCETYPE_DISK;
293 nr.lpLocalName=szDriveToMapTo;
294 nr.lpRemoteName=szAfsPath;
295 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
296 nr.dwUsage = RESOURCEUSAGE_CONNECTABLE;
298 dwResult = WNetAddConnection2(&nr,NULL,NULL,FALSE);
301 afsi_log("GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
308 typedef BOOL ( APIENTRY * AfsdInitHook )(void);
309 #define AFSD_INIT_HOOK "AfsdInitHook"
310 #define AFSD_HOOK_DLL "afsdhook.dll"
312 void afsd_Main(DWORD argc, LPTSTR *argv)
318 AfsdInitHook initHook;
321 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
322 _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
325 osi_InitPanic(afsd_notifier);
326 osi_InitTraceOption();
330 WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
331 if ( GetLastError() == ERROR_ALREADY_EXISTS )
332 afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
335 StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME,
336 (LPHANDLER_FUNCTION_EX) afsd_ServiceControlHandlerEx,
337 NULL /* user context */
340 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
341 ServiceStatus.dwServiceSpecificExitCode = 0;
342 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
343 ServiceStatus.dwWin32ExitCode = NO_ERROR;
344 ServiceStatus.dwCheckPoint = 1;
345 ServiceStatus.dwWaitHint = 30000;
346 /* accept Power Events */
347 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
348 SetServiceStatus(StatusHandle, &ServiceStatus);
352 HANDLE h; char *ptbuf[1];
353 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
354 ptbuf[0] = "AFS start pending";
355 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
356 DeregisterEventSource(h);
359 #ifdef REGISTER_POWER_NOTIFICATIONS
360 /* create thread used to flush cache */
361 PowerNotificationThreadCreate();
366 /* allow an exit to be called prior to any initialization */
367 hInitHookDll = LoadLibrary(AFSD_HOOK_DLL);
371 initHook = ( AfsdInitHook ) GetProcAddress(hInitHookDll, AFSD_INIT_HOOK);
376 FreeLibrary(hInitHookDll);
380 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
381 ServiceStatus.dwWin32ExitCode = NO_ERROR;
382 ServiceStatus.dwCheckPoint = 0;
383 ServiceStatus.dwWaitHint = 0;
384 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
385 SetServiceStatus(StatusHandle, &ServiceStatus);
387 /* exit if initialization failed */
392 /* allow another 15 seconds to start */
393 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
394 ServiceStatus.dwServiceSpecificExitCode = 0;
395 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
396 ServiceStatus.dwWin32ExitCode = NO_ERROR;
397 ServiceStatus.dwCheckPoint = 2;
398 ServiceStatus.dwWaitHint = 15000;
399 ServiceStatus.dwControlsAccepted = 0;
400 SetServiceStatus(StatusHandle, &ServiceStatus);
404 MainThreadId = GetCurrentThreadId();
405 jmpret = setjmp(notifier_jmp);
408 code = afsd_InitCM(&reason);
410 osi_panic(reason, __FILE__, __LINE__);
413 ServiceStatus.dwCheckPoint++;
414 ServiceStatus.dwWaitHint -= 5000;
415 SetServiceStatus(StatusHandle, &ServiceStatus);
417 code = afsd_InitDaemons(&reason);
419 osi_panic(reason, __FILE__, __LINE__);
422 ServiceStatus.dwCheckPoint++;
423 ServiceStatus.dwWaitHint -= 5000;
424 SetServiceStatus(StatusHandle, &ServiceStatus);
426 code = afsd_InitSMB(&reason, DummyMessageBox);
428 osi_panic(reason, __FILE__, __LINE__);
431 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
432 ServiceStatus.dwWin32ExitCode = NO_ERROR;
433 ServiceStatus.dwCheckPoint = 0;
434 ServiceStatus.dwWaitHint = 0;
436 /* accept Power events */
437 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
438 SetServiceStatus(StatusHandle, &ServiceStatus);
441 HANDLE h; char *ptbuf[1];
442 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
443 ptbuf[0] = "AFS running";
444 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
445 DeregisterEventSource(h);
449 /* Check if we should mount a drive into AFS */
452 WaitForSingleObject(WaitToTerminate, INFINITE);
455 HANDLE h; char *ptbuf[1];
456 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
457 ptbuf[0] = "AFS quitting";
458 ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
459 0, 0, NULL, 1, 0, ptbuf, NULL);
460 DeregisterEventSource(h);
463 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
464 ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
465 ServiceStatus.dwCheckPoint = 0;
466 ServiceStatus.dwWaitHint = 0;
467 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
469 /* also now accept Power events - shutdown maybe? */
470 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
472 #ifdef REGISTER_POWER_NOTIFICATIONS
473 /* terminate thread used to flush cache */
474 PowerNotificationThreadExit();
477 SetServiceStatus(StatusHandle, &ServiceStatus);
480 DWORD __stdcall afsdMain_thread(void* notUsed)
482 afsd_Main(0, (LPTSTR*)NULL);
488 SERVICE_TABLE_ENTRY dispatchTable[] = {
489 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
493 afsd_SetUnhandledExceptionFilter();
495 if (!StartServiceCtrlDispatcher(dispatchTable))
497 LONG status = GetLastError();
498 if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
501 CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
503 printf("Hit <Enter> to terminate OpenAFS Client Service\n");
505 SetEvent(WaitToTerminate);