Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1037 lines
29 KiB

  1. /*++
  2. Copyright (c) 1995-1997 Microsoft Corporation
  3. Module Name:
  4. resmon.c
  5. Abstract:
  6. Startup and initialization portion of the Cluster Resource Monitor
  7. Author:
  8. John Vert (jvert) 30-Nov-1995
  9. Revision History:
  10. Sivaprasad Padisetty (sivapad) 06-18-1997 Added the COM support
  11. --*/
  12. #include "nt.h"
  13. #include "ntrtl.h"
  14. #include "nturtl.h"
  15. #include "resmonp.h"
  16. #include "stdio.h"
  17. #include "stdlib.h"
  18. #include "clusverp.h"
  19. #ifdef COMRES
  20. #include "comres_i.c"
  21. #endif
  22. #define RESMON_MODULE RESMON_MODULE_RESMON
  23. //
  24. // Global data
  25. //
  26. CRITICAL_SECTION RmpListLock;
  27. LOCK_INFO RmpListPPrevPrevLock;
  28. LOCK_INFO RmpListPrevPrevLock;
  29. LOCK_INFO RmpListPrevLock;
  30. LOCK_INFO RmpListLastLock;
  31. LOCK_INFO RmpListLastUnlock;
  32. LOCK_INFO RmpListPrevUnlock;
  33. LOCK_INFO RmpListPrevPrevUnlock;
  34. LOCK_INFO RmpListPPrevPrevUnlock;
  35. CRITICAL_SECTION RmpMonitorStateLock;
  36. PMONITOR_STATE RmpSharedState = NULL;
  37. HANDLE RmpInitEvent = NULL;
  38. HANDLE RmpFileMapping = NULL;
  39. HANDLE RmpClusterProcess = NULL;
  40. HKEY RmpResourcesKey = NULL;
  41. HKEY RmpResTypesKey = NULL;
  42. HCLUSTER RmpHCluster = NULL;
  43. HANDLE RmpWaitArray[MAX_THREADS];
  44. HANDLE RmpRewaitEvent = NULL;
  45. DWORD RmpNumberOfThreads = 0;
  46. BOOL RmpDebugger = FALSE;
  47. BOOL RmpCrashed = FALSE;
  48. LPTOP_LEVEL_EXCEPTION_FILTER lpfnOriginalExceptionFilter = NULL;
  49. PWCHAR RmonStates[] = {
  50. L"", // Initializing
  51. L"", // Idle
  52. L"Starting",
  53. L"Initializing",
  54. L"Online",
  55. L"Offline",
  56. L"Shutdown",
  57. L"Deleteing",
  58. L"IsAlivePoll",
  59. L"LooksAlivePoll",
  60. L"Arbitrate",
  61. L"Release"
  62. L"ResourceControl",
  63. L"ResourceTypeControl",
  64. 0 };
  65. //
  66. // Prototypes local to this module
  67. //
  68. DWORD
  69. RmpInitialize(
  70. VOID
  71. );
  72. VOID
  73. RmpCleanup(
  74. VOID
  75. );
  76. VOID
  77. RmpParseArgs(
  78. int argc,
  79. wchar_t *argv[],
  80. OUT LPDWORD pClussvcProcessId,
  81. OUT HANDLE* pClussvcFileMapping,
  82. OUT HANDLE* pClussvcInitEvent,
  83. OUT LPWSTR* pDebuggerCommand
  84. );
  85. LONG
  86. RmpExceptionFilter(
  87. IN PEXCEPTION_POINTERS ExceptionInfo
  88. )
  89. /*++
  90. Routine Description:
  91. Top level exception handler for the resource monitor process.
  92. Currently this just exits immediately and assumes that the
  93. cluster service will notice and clean up the mess.
  94. Arguments:
  95. ExceptionInfo - Supplies the exception information
  96. Return Value:
  97. None.
  98. --*/
  99. {
  100. DWORD code = 0;
  101. if ( !RmpCrashed ) {
  102. RmpCrashed = TRUE;
  103. code = ExceptionInfo->ExceptionRecord->ExceptionCode;
  104. ClRtlLogPrint( LOG_CRITICAL, "[RM] Exception. Code = 0x%1!lx!, Address = 0x%2!lx!\n",
  105. ExceptionInfo->ExceptionRecord->ExceptionCode,
  106. ExceptionInfo->ExceptionRecord->ExceptionAddress);
  107. ClRtlLogPrint( LOG_CRITICAL, "[RM] Exception parameters: %1!lx!, %2!lx!, %3!lx!, %4!lx!\n",
  108. ExceptionInfo->ExceptionRecord->ExceptionInformation[0],
  109. ExceptionInfo->ExceptionRecord->ExceptionInformation[1],
  110. ExceptionInfo->ExceptionRecord->ExceptionInformation[2],
  111. ExceptionInfo->ExceptionRecord->ExceptionInformation[3]);
  112. CL_LOGFAILURE(ExceptionInfo->ExceptionRecord->ExceptionCode);
  113. if (lpfnOriginalExceptionFilter)
  114. lpfnOriginalExceptionFilter(ExceptionInfo);
  115. }
  116. //
  117. // Dump an exception report
  118. //
  119. GenerateExceptionReport(ExceptionInfo);
  120. //
  121. // Try to dump the resource and the resource state
  122. //
  123. try {
  124. PRESOURCE resource;
  125. DWORD state = 0;
  126. resource = (PRESOURCE)RmpSharedState->ActiveResource;
  127. if ( state <= RmonResourceTypeControl ) {
  128. state =RmpSharedState->State;
  129. }
  130. ClRtlLogPrint( LOG_CRITICAL, "[RM] Active Resource = %1!08LX!\n",
  131. resource );
  132. ClRtlLogPrint( LOG_CRITICAL, "[RM] Resource State is %1!u!, \"%2!ws!\"\n",
  133. RmpSharedState->State,
  134. RmonStates[RmpSharedState->State] );
  135. if ( resource ) {
  136. ClRtlLogPrint( LOG_CRITICAL, "[RM] Resource name is %1!ws!\n",
  137. resource->ResourceName );
  138. ClRtlLogPrint( LOG_CRITICAL, "[RM] Resource type is %1!ws!\n",
  139. resource->ResourceType );
  140. }
  141. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  142. ClRtlLogPrint( LOG_CRITICAL, "[RM] Exception %1!08LX! while dumping state for resource!\n",
  143. GetExceptionCode());
  144. }
  145. if ( code == 0xC0000194 ) {
  146. DumpCriticalSection( (PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[0] );
  147. }
  148. if ( IsDebuggerPresent()) {
  149. return(EXCEPTION_CONTINUE_SEARCH);
  150. } else {
  151. #if !CLUSTER_BETA
  152. // terminate only when product ships
  153. TerminateProcess( GetCurrentProcess(),
  154. ExceptionInfo->ExceptionRecord->ExceptionCode );
  155. #endif
  156. return(EXCEPTION_CONTINUE_SEARCH);
  157. }
  158. }
  159. int _cdecl
  160. wmain (argc, argv)
  161. int argc;
  162. wchar_t *argv[];
  163. {
  164. PVOID EventList;
  165. DWORD Status;
  166. HANDLE ResourceId;
  167. CLUSTER_RESOURCE_STATE ResourceState;
  168. WCHAR rpcEndpoint[80];
  169. HKEY ClusterKey;
  170. BOOL Inited = FALSE;
  171. BOOL comInited = FALSE;
  172. BOOL bSuccess;
  173. HANDLE ClussvcFileMapping, ClussvcInitEvent;
  174. DWORD ClussvcProcessId;
  175. LPWSTR debuggerCommand = NULL;
  176. //
  177. // Initialize the Cluster Rtl routines.
  178. //
  179. if ( (Status = ClRtlInitialize( FALSE, NULL )) != ERROR_SUCCESS ) {
  180. ClRtlLogPrint(LOG_CRITICAL,
  181. "[RM] Failed to initialize Cluster RTL, error %1!u!.\n",
  182. Status);
  183. goto init_failure;
  184. }
  185. ClRtlInitWmi(NULL);
  186. Inited = TRUE;
  187. //
  188. // Parse the input arguments.
  189. //
  190. RmpParseArgs(argc, argv,
  191. &ClussvcProcessId,
  192. &ClussvcFileMapping,
  193. &ClussvcInitEvent,
  194. &debuggerCommand);
  195. if ((ClussvcInitEvent == NULL) ||
  196. (ClussvcFileMapping == NULL) ||
  197. (ClussvcProcessId == 0)) {
  198. //
  199. // All of these arguments are required.
  200. //
  201. ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to parse required parameter.\n");
  202. Status = ERROR_INVALID_PARAMETER;
  203. goto init_failure;
  204. }
  205. //
  206. // We do not want to create resmon process with InheritHandles flag.
  207. // So resmon parameters got changed. We no longer pass handles valid in
  208. // the context of resmon.
  209. //
  210. //
  211. // First, convert ProcessId into ProcessHandle
  212. //
  213. RmpClusterProcess = OpenProcess(PROCESS_ALL_ACCESS,
  214. FALSE, // Don't inherit
  215. ClussvcProcessId);
  216. if (RmpClusterProcess == NULL) {
  217. Status = GetLastError();
  218. ClRtlLogPrint( LOG_CRITICAL, "[RM] OpenProcess for %1!x! process failed, error %2!u!.\n",
  219. RmpClusterProcess, Status);
  220. goto init_failure;
  221. }
  222. //
  223. // Now Dup the handles from ClusSvc to Resmon
  224. //
  225. bSuccess = DuplicateHandle(
  226. RmpClusterProcess, // Source Process
  227. ClussvcInitEvent, // Source Handle
  228. GetCurrentProcess(),// Target Process
  229. &RmpInitEvent, // Target Handle
  230. 0, // DUPLICATE_SAME_ACCESS
  231. FALSE, // Don't inherit
  232. DUPLICATE_SAME_ACCESS);
  233. if (!bSuccess) {
  234. Status = GetLastError();
  235. ClRtlLogPrint( LOG_CRITICAL, "[RM] Dup InitEvent handle %1!x! failed, error %2!u!.\n",
  236. ClussvcInitEvent, Status);
  237. goto init_failure;
  238. }
  239. bSuccess = DuplicateHandle(
  240. RmpClusterProcess, // Source Process
  241. ClussvcFileMapping, // Source Handle
  242. GetCurrentProcess(),// Target Process
  243. &RmpFileMapping, // Target Handle
  244. 0, // DUPLICATE_SAME_ACCESS
  245. FALSE, // Don't inherit
  246. DUPLICATE_SAME_ACCESS);
  247. if (!bSuccess) {
  248. Status = GetLastError();
  249. ClRtlLogPrint( LOG_CRITICAL, "[RM] Dup FileMapping handle %1!x! failed, error %2!u!.\n",
  250. ClussvcFileMapping, Status);
  251. goto init_failure;
  252. }
  253. if ( debuggerCommand ) {
  254. //
  255. // if -d was specified, then check if the optional command arg was
  256. // specified. If not, wait for a debugger to be attached
  257. // external. Otherwise, append the PID to the passed command and call
  258. // CreateProcess on it.
  259. //
  260. if ( *debuggerCommand == UNICODE_NULL ) {
  261. while ( !IsDebuggerPresent()) {
  262. Sleep( 1000 );
  263. }
  264. } else {
  265. STARTUPINFOW startupInfo;
  266. PROCESS_INFORMATION processInfo;
  267. DWORD cmdLength;
  268. PWCHAR dbgCmdLine;
  269. cmdLength = wcslen( debuggerCommand );
  270. dbgCmdLine = LocalAlloc( LMEM_FIXED, ( cmdLength + 24 ) * sizeof( WCHAR ));
  271. if ( dbgCmdLine != NULL ) {
  272. wsprintfW(dbgCmdLine, L"%ws -p %d", debuggerCommand, GetCurrentProcessId());
  273. ClRtlLogPrint(LOG_NOISE, "[RM] Starting debugger process: %1!ws!\n", dbgCmdLine );
  274. //
  275. // Attempt to attach debugger to us
  276. //
  277. ZeroMemory(&startupInfo, sizeof(startupInfo));
  278. startupInfo.cb = sizeof(startupInfo);
  279. bSuccess = CreateProcessW(NULL,
  280. dbgCmdLine,
  281. NULL,
  282. NULL,
  283. FALSE, // Inherit handles
  284. DETACHED_PROCESS, // so ctrl-c won't kill it
  285. NULL,
  286. NULL,
  287. &startupInfo,
  288. &processInfo);
  289. if (!bSuccess) {
  290. Status = GetLastError();
  291. ClRtlLogPrint(LOG_UNUSUAL,
  292. "[RM] Failed to create debugger process, error %1!u!.\n",
  293. Status);
  294. }
  295. CloseHandle(processInfo.hThread); // don't need these
  296. CloseHandle(processInfo.hProcess);
  297. LocalFree( dbgCmdLine );
  298. } else {
  299. ClRtlLogPrint(LOG_UNUSUAL,
  300. "[RM] Failed to alloc memory for debugger command line, error %1!u!.\n",
  301. GetLastError());
  302. }
  303. }
  304. }
  305. //
  306. // init COM for netname
  307. //
  308. Status = CoInitializeEx( NULL, COINIT_DISABLE_OLE1DDE | COINIT_MULTITHREADED );
  309. if ( !SUCCEEDED( Status )) {
  310. ClRtlLogPrint( LOG_CRITICAL, "[RM] Couldn't init COM %1!08X!\n", Status );
  311. goto init_failure;
  312. }
  313. comInited = TRUE;
  314. ClRtlLogPrint( LOG_NOISE, "[RM] Main: Initializing.\r\n");
  315. //
  316. // Initialize the resource monitor.
  317. //
  318. Status = RmpInitialize();
  319. if ( Status != ERROR_SUCCESS ) {
  320. ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to initialize, error %1!u!.\n",
  321. Status);
  322. goto init_failure;
  323. }
  324. RmpSharedState = MapViewOfFile(RmpFileMapping,
  325. FILE_MAP_WRITE,
  326. 0,
  327. 0,
  328. 0);
  329. if (RmpSharedState == NULL) {
  330. ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to init shared state, error %1!u!.\n",
  331. Status = GetLastError());
  332. goto init_failure;
  333. }
  334. CloseHandle(RmpFileMapping);
  335. RmpFileMapping = NULL;
  336. GetSystemTimeAsFileTime((PFILETIME)&RmpSharedState->LastUpdate);
  337. RmpSharedState->State = RmonInitializing;
  338. RmpSharedState->ActiveResource = NULL;
  339. if ( RmpSharedState->ResmonStop ) {
  340. // If ResmonStop is set to TRUE, then a debugger should be attached
  341. RmpDebugger = TRUE;
  342. }
  343. //
  344. // Connect to local cluster and open Resources key.
  345. //
  346. RmpHCluster = OpenCluster(NULL);
  347. if (RmpHCluster == NULL) {
  348. Status = GetLastError();
  349. ClRtlLogPrint( LOG_CRITICAL, "[RM] Error opening cluster, error %1!u!.\n",
  350. Status);
  351. goto init_failure;
  352. }
  353. ClusterKey = GetClusterKey(RmpHCluster, KEY_READ);
  354. if (ClusterKey == NULL) {
  355. Status = GetLastError();
  356. ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to open the cluster key, error %1!u!.\n",
  357. Status);
  358. goto init_failure;
  359. }
  360. Status = ClusterRegOpenKey(ClusterKey,
  361. CLUSREG_KEYNAME_RESOURCES,
  362. KEY_READ,
  363. &RmpResourcesKey);
  364. if (Status != ERROR_SUCCESS) {
  365. ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to open Resources cluster registry key, error %1!u!.\n",
  366. Status);
  367. goto init_failure;
  368. }
  369. Status = ClusterRegOpenKey(ClusterKey,
  370. CLUSREG_KEYNAME_RESOURCE_TYPES,
  371. KEY_READ,
  372. &RmpResTypesKey);
  373. if (Status != ERROR_SUCCESS) {
  374. ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to open ResourceTypes cluster registry key, error %1!u!.\n",
  375. Status);
  376. goto init_failure;
  377. }
  378. //
  379. // The Wait Count identifies the number of events the main thread will
  380. // wait for. This is the notification event, the Cluster Service Process
  381. // plus each event list thread. We start at 2 because the first two entries
  382. // are fixed - for the notification event and the Cluster Service process.
  383. //
  384. RmpNumberOfThreads = 2;
  385. //
  386. // Create an event to be signaled whenever we add a new thread.
  387. //
  388. RmpRewaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  389. if ( RmpRewaitEvent == NULL ) {
  390. ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to create rewait event, error %1!u!.\n",
  391. Status = GetLastError());
  392. goto init_failure;
  393. }
  394. //
  395. // Create the first event list, and start a polling thread.
  396. //
  397. EventList = RmpCreateEventList();
  398. if (EventList == NULL) {
  399. ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to create event list, error %1!u!.\n",
  400. Status = GetLastError());
  401. goto init_failure;
  402. }
  403. //
  404. // Start RPC Server
  405. //
  406. wsprintfW( rpcEndpoint, L"resrcmon%d", GetCurrentProcessId());
  407. Status = RpcServerUseProtseqEpW(L"ncalrpc",
  408. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  409. rpcEndpoint,
  410. NULL);
  411. if (Status != RPC_S_OK) {
  412. ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to initialize RPC interface, error %1!u!.\n",
  413. Status);
  414. goto init_failure;
  415. }
  416. Status = RpcServerRegisterIf(s_resmon_v2_0_s_ifspec,
  417. NULL,
  418. NULL);
  419. if (Status != RPC_S_OK) {
  420. ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to register RPC interface, error %1!u!.\n",
  421. Status);
  422. goto init_failure;
  423. }
  424. Status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE);
  425. if (Status != RPC_S_OK) {
  426. ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to set RPC server listening, error %1!u!.\n",
  427. Status);
  428. goto init_failure;
  429. }
  430. //
  431. // Set our unhandled exception filter so that if anything horrible
  432. // goes wrong, we can exit immediately.
  433. //
  434. lpfnOriginalExceptionFilter = SetUnhandledExceptionFilter(RmpExceptionFilter);
  435. //
  436. // Set the event to indicate that our initialization is complete.
  437. // This event is passed on the command line.
  438. //
  439. if (!SetEvent(RmpInitEvent)) {
  440. ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to signal cluster service event, error %1!u!.\n",
  441. Status = GetLastError());
  442. goto init_failure;
  443. }
  444. CloseHandle(RmpInitEvent);
  445. //
  446. // ResmonStop is initialized to TRUE by ClusSvc, we will wait for
  447. // ClusSvc to signal when it is done attaching a debugger by waiting
  448. // until ResmonStop is set to FALSE.
  449. //
  450. while ( RmpSharedState->ResmonStop ) {
  451. Sleep(100);
  452. }
  453. //
  454. // Boost our priority. Non-fatal if this fails.
  455. //
  456. if ( !SetPriorityClass( GetCurrentProcess(),
  457. HIGH_PRIORITY_CLASS ) ) {
  458. ClRtlLogPrint( LOG_UNUSUAL, "[RM] Failed to set priority class, error %1!u!.\n",
  459. GetLastError() );
  460. }
  461. //
  462. // Wait for shutdown. Either the cluster service terminating or
  463. // the poller thread terminating will initiate a shutdown.
  464. //
  465. RmpWaitArray[0] = RmpRewaitEvent;
  466. RmpWaitArray[1] = RmpClusterProcess;
  467. //
  468. // If we are notified a new thread is added, then just re-wait.
  469. // N.B. RmpNumberOfThreads is really the number of threads, plus the
  470. // two fixed wait events (the change notification and the Cluster Service).
  471. //
  472. do {
  473. Status = WaitForMultipleObjects(RmpNumberOfThreads,
  474. RmpWaitArray,
  475. FALSE,
  476. INFINITE);
  477. } while ( (Status == WAIT_OBJECT_0) && (RmpShutdown == FALSE) );
  478. ClRtlLogPrint( LOG_UNUSUAL, "[RM] Going away, Status = %1!u!, Shutdown = %2!u!.\n",
  479. Status, RmpShutdown);
  480. RmpShutdown = TRUE;
  481. CloseHandle( RmpRewaitEvent );
  482. //
  483. // Initiate RM shutdown.
  484. //
  485. s_RmShutdownProcess(NULL);
  486. //
  487. // Clean up any resources left lying around by the cluster service.
  488. //
  489. RmpRundownResources();
  490. //
  491. // Shutdown RPC Server
  492. //
  493. RpcMgmtStopServerListening(NULL);
  494. RpcServerUnregisterIf(NULL, NULL, TRUE);
  495. CoUninitialize () ;
  496. return(0);
  497. init_failure:
  498. if ( RmpInitEvent != NULL ) {
  499. CloseHandle( RmpInitEvent );
  500. }
  501. if ( RmpFileMapping != NULL ) {
  502. CloseHandle( RmpFileMapping );
  503. }
  504. if ( RmpClusterProcess != NULL ) {
  505. CloseHandle( RmpClusterProcess );
  506. }
  507. if ( RmpResTypesKey != NULL ) {
  508. ClusterRegCloseKey( RmpResTypesKey );
  509. }
  510. if ( RmpResourcesKey != NULL ) {
  511. ClusterRegCloseKey( RmpResourcesKey );
  512. }
  513. if ( RmpHCluster != NULL ) {
  514. CloseCluster( RmpHCluster );
  515. }
  516. if ( RmpRewaitEvent != NULL ) {
  517. CloseHandle( RmpRewaitEvent );
  518. }
  519. if ( comInited )
  520. CoUninitialize();
  521. if ( Inited )
  522. CL_LOGFAILURE(Status);
  523. return(Status);
  524. } // main
  525. VOID
  526. RmpParseArgs(
  527. int argc,
  528. wchar_t *argv[],
  529. OUT LPDWORD pClussvcProcessId,
  530. OUT HANDLE* pClussvcFileMapping,
  531. OUT HANDLE* pClussvcInitEvent,
  532. OUT LPWSTR* pDebuggerCommand
  533. )
  534. /*++
  535. Routine Description:
  536. Parses the command line passed to the resource monitor
  537. Required options:
  538. -e EVENT supplies Event handle to be signalled when
  539. initialization is complete
  540. -m FILEMAPPING supplies file mapping handle to be
  541. used for shared monitor state.
  542. -p PROCESSID supplies process id of the cluster
  543. service so resmon can detect failure of the
  544. cluster service and shutdown cleanly.
  545. -d [DEBUGGERCMD] - wait for or attach a debugger during startup
  546. Additional options:
  547. none
  548. Arguments:
  549. argc - supplies number of arguments
  550. argv - supplies actual arguments
  551. Return Value:
  552. None.
  553. --*/
  554. {
  555. int i;
  556. wchar_t *p;
  557. for (i=1; i<argc; i++) {
  558. p=argv[i];
  559. if ((*p == '-') ||
  560. (*p == '/')) {
  561. ++p;
  562. switch (toupper(*p)) {
  563. case 'E':
  564. if (i+1 < argc) {
  565. *pClussvcInitEvent = LongToHandle(_wtoi(argv[++i]));
  566. } else {
  567. goto BadCommandLine;
  568. }
  569. break;
  570. case 'M':
  571. if (i+1 < argc) {
  572. *pClussvcFileMapping = LongToHandle(_wtoi(argv[++i]));
  573. } else {
  574. goto BadCommandLine;
  575. }
  576. break;
  577. case 'P':
  578. if (i+1 < argc) {
  579. *pClussvcProcessId = (DWORD)_wtoi(argv[++i]);
  580. } else {
  581. goto BadCommandLine;
  582. }
  583. break;
  584. case 'D':
  585. //
  586. // use the empty (but not NULL) string to indicate that
  587. // resmon should wait for a debugger to be attached.
  588. //
  589. if (i+1 < argc) {
  590. if ( *argv[i+1] != UNICODE_NULL && *argv[i+1] != L'-' ) {
  591. *pDebuggerCommand = argv[++i];
  592. } else {
  593. *pDebuggerCommand = L"";
  594. }
  595. } else {
  596. *pDebuggerCommand = L"";
  597. }
  598. break;
  599. default:
  600. goto BadCommandLine;
  601. }
  602. }
  603. }
  604. return;
  605. BadCommandLine:
  606. ClusterLogEvent0(LOG_CRITICAL,
  607. LOG_CURRENT_MODULE,
  608. __FILE__,
  609. __LINE__,
  610. RMON_INVALID_COMMAND_LINE,
  611. 0,
  612. NULL);
  613. ExitProcess(0);
  614. } // RmpParseArgs
  615. DWORD
  616. RmpInitialize(
  617. VOID
  618. )
  619. /*++
  620. Routine Description:
  621. Initialize all resources needed by the resource monitor.
  622. Arguments:
  623. None.
  624. Returns:
  625. ERROR_SUCCESS if successful.
  626. Win32 error code on failure.
  627. --*/
  628. {
  629. //
  630. // Initialize global data
  631. //
  632. InitializeCriticalSection(&RmpListLock);
  633. InitializeCriticalSection(&RmpMonitorStateLock);
  634. InitializeListHead(&RmpEventListHead);
  635. ClRtlInitializeQueue(&RmpNotifyQueue);
  636. return(ERROR_SUCCESS);
  637. } // RmpInitialize
  638. VOID
  639. RmpCleanup(
  640. VOID
  641. )
  642. /*++
  643. Routine Description:
  644. Cleanup all resources created during init.
  645. Arguments:
  646. None.
  647. Returns:
  648. None.
  649. --*/
  650. {
  651. } // RmpCleanup
  652. DWORD RmpLoadResType(
  653. IN LPCWSTR lpszResourceTypeName,
  654. IN LPCWSTR lpszDllName,
  655. OUT PRESDLL_FNINFO pResDllFnInfo,
  656. #ifdef COMRES
  657. OUT PRESDLL_INTERFACES pResDllInterfaces,
  658. #endif
  659. OUT LPDWORD pdwCharacteristics
  660. )
  661. {
  662. DWORD retry;
  663. DWORD dwStatus = ERROR_SUCCESS;
  664. HINSTANCE hDll = NULL;
  665. PSTARTUP_ROUTINE pfnStartup;
  666. PCLRES_FUNCTION_TABLE pFnTable = NULL;
  667. LPWSTR pszDllName = (LPWSTR) lpszDllName;
  668. pResDllFnInfo->hDll = NULL;
  669. pResDllFnInfo->pResFnTable = NULL;
  670. #ifdef COMRES
  671. pResDllInterfaces->pClusterResource = NULL;
  672. pResDllInterfaces->pClusterQuorumResource = NULL;
  673. pResDllInterfaces->pClusterResControl = NULL;
  674. #endif
  675. // Expand any environment variables included in the DLL path name.
  676. if ( wcschr( lpszDllName, L'%' ) != NULL ) {
  677. pszDllName = ClRtlExpandEnvironmentStrings( lpszDllName );
  678. if ( pszDllName == NULL ) {
  679. dwStatus = GetLastError();
  680. ClRtlLogPrint( LOG_UNUSUAL, "[RM] ResTypeControl: Error expanding environment strings in '%1!ls!, error %2!u!.\n",
  681. lpszDllName,
  682. dwStatus);
  683. goto FnExit;
  684. }
  685. }
  686. // Load the dll... we can't assume we have the DLL loaded!
  687. hDll = LoadLibraryW(pszDllName);
  688. if ( hDll == NULL )
  689. {
  690. dwStatus = GetLastError();
  691. ClRtlLogPrint( LOG_CRITICAL, "[RM] ResTypeControl: Error loading resource DLL '%1!ls!, error %2!u!.\n",
  692. pszDllName,
  693. dwStatus);
  694. #ifdef COMRES
  695. dwStatus = RmpLoadComResType(lpszDllName, pResDllInterfaces,
  696. pdwCharacteristics);
  697. #endif
  698. goto FnExit;
  699. }
  700. //
  701. // Invoke debugger if one is specified.
  702. //
  703. if ( RmpDebugger ) {
  704. //
  705. // Wait for debugger to come online.
  706. //
  707. retry = 100;
  708. while ( retry-- &&
  709. !IsDebuggerPresent() ) {
  710. Sleep(100);
  711. }
  712. OutputDebugStringA("[RM] ResourceTypeControl: Just loaded resource DLL ");
  713. OutputDebugStringW(lpszDllName);
  714. OutputDebugStringA("\n");
  715. DebugBreak();
  716. }
  717. // Get the startup routine
  718. pfnStartup = (PSTARTUP_ROUTINE)GetProcAddress( hDll,
  719. STARTUP_ROUTINE );
  720. if ( pfnStartup == NULL ) {
  721. dwStatus = GetLastError();
  722. ClRtlLogPrint( LOG_CRITICAL, "[RM] ResTypeControl: Error getting startup routine, status %1!u!.\n",
  723. dwStatus);
  724. goto FnExit;
  725. }
  726. // Get the function table
  727. RmpSetMonitorState(RmonStartingResource, NULL);
  728. try {
  729. dwStatus = (pfnStartup)( lpszResourceTypeName,
  730. CLRES_VERSION_V1_00,
  731. CLRES_VERSION_V1_00,
  732. RmpSetResourceStatus,
  733. RmpLogEvent,
  734. &pFnTable );
  735. } except (EXCEPTION_EXECUTE_HANDLER) {
  736. dwStatus = GetExceptionCode();
  737. }
  738. RmpSetMonitorState(RmonIdle, NULL);
  739. if ( dwStatus != ERROR_SUCCESS ) {
  740. ClRtlLogPrint( LOG_CRITICAL, "[RM] ResTypeControl: Startup call failed, error %1!u!.\n",
  741. dwStatus);
  742. goto FnExit;
  743. }
  744. if ( pFnTable == NULL ) {
  745. ClRtlLogPrint( LOG_CRITICAL, "[RM] ResTypeControl: Startup function table is NULL!\n");
  746. dwStatus = ERROR_INVALID_DATA;
  747. goto FnExit;
  748. }
  749. if ( pFnTable->Version != CLRES_VERSION_V1_00 ) {
  750. ClRtlLogPrint( LOG_CRITICAL, "[RM] ResTypeControl: Incorrect function table version!\n");
  751. dwStatus = ERROR_INVALID_DATA;
  752. goto FnExit;
  753. }
  754. if ( pFnTable->TableSize != CLRES_V1_FUNCTION_SIZE ) {
  755. ClRtlLogPrint( LOG_CRITICAL, "[RM] ResTypeControl: Incorrect function table size!\n");
  756. dwStatus = ERROR_INVALID_DATA;
  757. goto FnExit;
  758. }
  759. if ( (pFnTable->V1Functions.Arbitrate != NULL) &&
  760. (pFnTable->V1Functions.Release != NULL) && pdwCharacteristics) {
  761. *pdwCharacteristics = CLUS_CHAR_QUORUM;
  762. }
  763. FnExit:
  764. if (dwStatus != ERROR_SUCCESS)
  765. {
  766. if (hDll) FreeLibrary(hDll);
  767. if (pFnTable) LocalFree(pFnTable);
  768. }
  769. else
  770. {
  771. pResDllFnInfo->hDll = hDll;
  772. pResDllFnInfo->pResFnTable = pFnTable;
  773. }
  774. if ( pszDllName != lpszDllName )
  775. {
  776. LocalFree( pszDllName );
  777. }
  778. return(dwStatus);
  779. } //*** RmpLoadResType()
  780. #ifdef COMRES
  781. DWORD RmpLoadComResType(
  782. IN LPCWSTR lpszDllName,
  783. OUT PRESDLL_INTERFACES pResDllInterfaces,
  784. OUT LPDWORD pdwCharacteristics)
  785. {
  786. IClusterResource *pClusterResource = NULL ;
  787. IClusterQuorumResource *pClusterQuorumResource = NULL;
  788. IClusterResControl *pClusterResControl = NULL;
  789. HRESULT hr ;
  790. CLSID clsid ;
  791. DWORD Error ;
  792. pResDllInterfaces->pClusterResource = NULL;
  793. pResDllInterfaces->pClusterQuorumResource = NULL;
  794. pResDllInterfaces->pClusterResControl = NULL;
  795. hr = CLSIDFromProgID(lpszDllName, &clsid) ;
  796. if (FAILED (hr))
  797. {
  798. ClRtlLogPrint( LOG_UNUSUAL, "[RM] Error converting CLSIDFromProgID Prog ID %1!ws!, error %2!u!.\n",
  799. lpszDllName, hr);
  800. goto FnExit ;
  801. }
  802. if ((hr = CoCreateInstance (&clsid, NULL, CLSCTX_ALL, &IID_IClusterResource, (LPVOID *) &pClusterResource)) != S_OK)
  803. goto FnExit ;
  804. //not a mandatory interface
  805. hr = IClusterResource_QueryInterface (pClusterResource, &IID_IClusterQuorumResource, (LPVOID *) &pClusterQuorumResource) ;
  806. if (SUCCEEDED(hr))
  807. {
  808. if (pdwCharacteristics)
  809. *pdwCharacteristics = CLUS_CHAR_QUORUM;
  810. IClusterQuorumResource_Release (pClusterQuorumResource) ;
  811. }
  812. //not a mandatory interface
  813. hr = IClusterResource_QueryInterface (
  814. pClusterResource,
  815. &IID_IClusterResControl,
  816. (LPVOID *) &pClusterResControl
  817. ) ;
  818. if (SUCCEEDED(hr))
  819. {
  820. *pdwCharacteristics = CLUS_CHAR_QUORUM;
  821. IClusterQuorumResource_Release (pClusterResControl) ;
  822. }
  823. hr = S_OK;
  824. FnExit:
  825. if (hr != S_OK)
  826. {
  827. if (pClusterResource)
  828. IClusterResource_Release (pClusterResource) ;
  829. if (pClusterQuorumResource)
  830. IClusterQuorumResource_Release (pClusterQuorumResource) ;
  831. if (pClusterResControl)
  832. IClusterResControl_Release (pClusterResControl) ;
  833. }
  834. else
  835. {
  836. pResDllInterfaces->pClusterResource = pClusterResource;
  837. pResDllInterfaces->pClusterQuorumResource = pClusterQuorumResource;
  838. pResDllInterfaces->pClusterResControl = pClusterResControl;
  839. }
  840. return(hr);
  841. }
  842. #endif //enf of #ifdef COMRES