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;
53 * Notifier function for use by osi_panic
55 static void afsd_notifier(char *msgp, char *filep, long line)
62 sprintf(tbuffer, "Error at file %s, line %d: %s",
65 sprintf(tbuffer, "Error at unknown location: %s", msgp);
67 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
69 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL);
70 DeregisterEventSource(h);
74 osi_LogEnable(afsd_logp);
76 afsd_ForceTrace(TRUE);
82 SetEvent(WaitToTerminate);
84 if (GetCurrentThreadId() == MainThreadId)
85 longjmp(notifier_jmp, 1);
91 * For use miscellaneously in smb.c; need to do better
93 static int DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
98 static SERVICE_STATUS ServiceStatus;
99 static SERVICE_STATUS_HANDLE StatusHandle;
102 afsd_ServiceFlushVolume(DWORD dwlpEventData)
104 DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
107 ** If UI bit is not set, user interaction is not possible
108 ** BUT, since we are a NON-interactive service, and therefore
109 ** have NO user I/O, it doesn't much matter.
110 ** This benign code left here as example of how to find this out
112 BOOL bUI = (dwlpEventData & 1);
115 if ( PowerNotificationThreadNotify() )
122 /* flush was unsuccessful, or timeout - deny shutdown */
123 dwRet = ERROR_NETWORK_BUSY;
126 /* to deny hibernate, simply return
127 // any value besides NO_ERROR.
129 // dwRet = ERROR_NETWORK_BUSY;
136 ** Extended ServiceControlHandler that provides Event types
137 ** for monitoring Power events, for example.
140 afsd_ServiceControlHandlerEx(
148 DWORD dummyLen, doTrace;
150 DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
154 case SERVICE_CONTROL_STOP:
156 RpcMgmtStopServerListening(NULL);
158 /* Force trace if requested */
159 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
161 0, KEY_QUERY_VALUE, &parmKey);
162 if (code != ERROR_SUCCESS)
165 dummyLen = sizeof(doTrace);
166 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
168 (BYTE *) &doTrace, &dummyLen);
169 RegCloseKey (parmKey);
170 if (code != ERROR_SUCCESS)
173 afsd_ForceTrace(FALSE);
176 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
177 ServiceStatus.dwWin32ExitCode = NO_ERROR;
178 ServiceStatus.dwCheckPoint = 1;
179 ServiceStatus.dwWaitHint = 10000;
180 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
181 SetServiceStatus(StatusHandle, &ServiceStatus);
182 SetEvent(WaitToTerminate);
186 case SERVICE_CONTROL_INTERROGATE:
187 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
188 ServiceStatus.dwWin32ExitCode = NO_ERROR;
189 ServiceStatus.dwCheckPoint = 0;
190 ServiceStatus.dwWaitHint = 0;
191 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
192 SetServiceStatus(StatusHandle, &ServiceStatus);
196 /* XXX handle system shutdown */
197 /* XXX handle pause & continue */
198 case SERVICE_CONTROL_POWEREVENT:
201 ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
202 ** Return NO_ERROR == return TRUE for that message, i.e. accept request
203 ** Return any error code to deny request,
204 ** i.e. as if returning BROADCAST_QUERY_DENY
206 switch((int) dwEventType)
208 case PBT_APMQUERYSUSPEND:
209 case PBT_APMQUERYSTANDBY:
211 #ifdef REGISTER_POWER_NOTIFICATIONS
213 dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);
219 /* allow remaining case PBT_WhatEver */
222 case PBT_APMRESUMECRITICAL:
223 case PBT_APMRESUMESUSPEND:
224 case PBT_APMRESUMESTANDBY:
225 case PBT_APMBATTERYLOW:
226 case PBT_APMPOWERSTATUSCHANGE:
227 case PBT_APMOEMEVENT:
228 case PBT_APMRESUMEAUTOMATIC:
233 } /* end switch(ctrlCode) */
238 /* This code was moved to Drivemap.cpp*/
239 /* Mount a drive into AFS if the user wants us to */
240 /* DEE Could check first if we are run as SYSTEM */
241 void CheckMountDrive()
243 char szAfsPath[_MAX_PATH];
244 char szDriveToMapTo[5];
250 DWORD dwSubMountSize;
251 char szSubMount[256];
254 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
256 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
257 if (dwResult != ERROR_SUCCESS)
261 dwDriveSize = sizeof(szDriveToMapTo);
262 dwSubMountSize = sizeof(szSubMount);
263 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
264 if (dwResult != ERROR_MORE_DATA) {
265 if (dwResult != ERROR_SUCCESS) {
266 if (dwResult != ERROR_NO_MORE_ITEMS)
267 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
273 sprintf(szAfsPath, "\\Device\\LanmanRedirector\\%s\\%s-AFS\\%s", szDriveToMapTo, cm_HostName, szSubMount);
275 dwResult = DefineDosDevice(DDD_RAW_TARGET_PATH, szDriveToMapTo, szAfsPath);
279 memset (&nr, 0x00, sizeof(NETRESOURCE));
281 sprintf(szAfsPath,"\\\\%s-AFS\\%s",cm_HostName,szSubMount);
283 nr.dwScope = RESOURCE_GLOBALNET;
284 nr.dwType=RESOURCETYPE_DISK;
285 nr.lpLocalName=szDriveToMapTo;
286 nr.lpRemoteName=szAfsPath;
287 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
288 nr.dwUsage = RESOURCEUSAGE_CONNECTABLE;
290 dwResult = WNetAddConnection2(&nr,NULL,NULL,FALSE);
293 afsi_log("GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
300 typedef BOOL ( APIENTRY * AfsdInitHook )(void);
301 #define AFSD_INIT_HOOK "AfsdInitHook"
302 #define AFSD_HOOK_DLL "afsdhook.dll"
304 void afsd_Main(DWORD argc, LPTSTR *argv)
310 AfsdInitHook initHook;
313 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
314 _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
317 osi_InitPanic(afsd_notifier);
318 osi_InitTraceOption();
322 WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, NULL);
325 StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME,
326 (LPHANDLER_FUNCTION_EX) afsd_ServiceControlHandlerEx,
327 NULL /* user context */
330 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
331 ServiceStatus.dwServiceSpecificExitCode = 0;
332 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
333 ServiceStatus.dwWin32ExitCode = NO_ERROR;
334 ServiceStatus.dwCheckPoint = 1;
335 ServiceStatus.dwWaitHint = 30000;
336 /* accept Power Events */
337 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
338 SetServiceStatus(StatusHandle, &ServiceStatus);
342 HANDLE h; char *ptbuf[1];
343 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
344 ptbuf[0] = "AFS start pending";
345 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
346 DeregisterEventSource(h);
349 #ifdef REGISTER_POWER_NOTIFICATIONS
350 /* create thread used to flush cache */
351 PowerNotificationThreadCreate();
356 /* allow an exit to be called prior to any initialization */
357 hInitHookDll = LoadLibrary(AFSD_HOOK_DLL);
361 initHook = ( AfsdInitHook ) GetProcAddress(hInitHookDll, AFSD_INIT_HOOK);
366 FreeLibrary(hInitHookDll);
370 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
371 ServiceStatus.dwWin32ExitCode = NO_ERROR;
372 ServiceStatus.dwCheckPoint = 0;
373 ServiceStatus.dwWaitHint = 0;
374 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
375 SetServiceStatus(StatusHandle, &ServiceStatus);
377 /* exit if initialization failed */
382 /* allow another 15 seconds to start */
383 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
384 ServiceStatus.dwServiceSpecificExitCode = 0;
385 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
386 ServiceStatus.dwWin32ExitCode = NO_ERROR;
387 ServiceStatus.dwCheckPoint = 2;
388 ServiceStatus.dwWaitHint = 15000;
389 ServiceStatus.dwControlsAccepted = 0;
390 SetServiceStatus(StatusHandle, &ServiceStatus);
394 MainThreadId = GetCurrentThreadId();
395 jmpret = setjmp(notifier_jmp);
398 code = afsd_InitCM(&reason);
400 osi_panic(reason, __FILE__, __LINE__);
403 ServiceStatus.dwCheckPoint++;
404 ServiceStatus.dwWaitHint -= 5000;
405 SetServiceStatus(StatusHandle, &ServiceStatus);
407 code = afsd_InitDaemons(&reason);
409 osi_panic(reason, __FILE__, __LINE__);
412 ServiceStatus.dwCheckPoint++;
413 ServiceStatus.dwWaitHint -= 5000;
414 SetServiceStatus(StatusHandle, &ServiceStatus);
416 code = afsd_InitSMB(&reason, DummyMessageBox);
418 osi_panic(reason, __FILE__, __LINE__);
421 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
422 ServiceStatus.dwWin32ExitCode = NO_ERROR;
423 ServiceStatus.dwCheckPoint = 0;
424 ServiceStatus.dwWaitHint = 0;
426 /* accept Power events */
427 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
428 SetServiceStatus(StatusHandle, &ServiceStatus);
431 HANDLE h; char *ptbuf[1];
432 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
433 ptbuf[0] = "AFS running";
434 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
435 DeregisterEventSource(h);
439 /* Check if we should mount a drive into AFS */
442 WaitForSingleObject(WaitToTerminate, INFINITE);
445 HANDLE h; char *ptbuf[1];
446 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
447 ptbuf[0] = "AFS quitting";
448 ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
449 0, 0, NULL, 1, 0, ptbuf, NULL);
450 DeregisterEventSource(h);
453 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
454 ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
455 ServiceStatus.dwCheckPoint = 0;
456 ServiceStatus.dwWaitHint = 0;
457 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
459 /* also now accept Power events - shutdown maybe? */
460 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
462 #ifdef REGISTER_POWER_NOTIFICATIONS
463 /* terminate thread used to flush cache */
464 PowerNotificationThreadExit();
467 SetServiceStatus(StatusHandle, &ServiceStatus);
470 DWORD __stdcall afsdMain_thread(void* notUsed)
472 afsd_Main(0, (LPTSTR*)NULL);
478 SERVICE_TABLE_ENTRY dispatchTable[] = {
479 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
483 afsd_SetUnhandledExceptionFilter();
485 if (!StartServiceCtrlDispatcher(dispatchTable))
487 LONG status = GetLastError();
488 if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
491 CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
493 printf("Hit <Enter> to terminate OpenAFS Client Service\n");
495 SetEvent(WaitToTerminate);