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.

1777 lines
44 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corp.
  3. Module Name:
  4. clusres.c
  5. Abstract:
  6. Resource DLL for Remote Storage Server
  7. Author:
  8. Ravisankar Pudipeddi (ravisp) 1 Sept 1999
  9. Revision History:
  10. --*/
  11. #pragma comment(lib, "clusapi.lib")
  12. #pragma comment(lib, "resutils.lib")
  13. #define UNICODE 1
  14. #include <windows.h>
  15. #include <resapi.h>
  16. #include <stdio.h>
  17. #include "userenv.h"
  18. #include "winsvc.h"
  19. #define LOG_CURRENT_MODULE LOG_MODULE_RSCLUSTER
  20. #define SERVICES_ROOT L"SYSTEM\\CurrentControlSet\\Services\\"
  21. #define DBG_PRINT printf
  22. #pragma warning( disable : 4115 ) // named type definition in parentheses
  23. #pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
  24. #pragma warning( disable : 4214 ) // nonstandard extension used : bit field types other than int
  25. #pragma warning( default : 4214 ) // nonstandard extension used : bit field types other than int
  26. #pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
  27. #pragma warning( default : 4115 ) // named type definition in parentheses
  28. //
  29. // Type and constant definitions.
  30. //
  31. #define RSCLUSTER_RESNAME L"Remote Storage Server"
  32. #define RSCLUSTER_SVCNAME TEXT("Remote_Storage_Server")
  33. // Handle to service controller, set by the first create resource call.
  34. SC_HANDLE g_ScHandle = NULL;
  35. typedef struct _RSCLUSTER_RESOURCE {
  36. RESID ResId; // for validation
  37. HRESOURCE hResource;
  38. SC_HANDLE ServiceHandle;
  39. RESOURCE_HANDLE ResourceHandle;
  40. HKEY ResourceKey;
  41. HKEY ParametersKey;
  42. LPWSTR ResourceName;
  43. CLUS_WORKER PendingThread;
  44. BOOL Online;
  45. CLUS_WORKER OnlineThread;
  46. CLUSTER_RESOURCE_STATE State;
  47. DWORD dwServicePid;
  48. HANDLE hSem;
  49. } RSCLUSTER_RESOURCE, *PRSCLUSTER_RESOURCE;
  50. //
  51. // Global data.
  52. //
  53. // Event Logging routine.
  54. PLOG_EVENT_ROUTINE g_LogEvent = NULL;
  55. // Resource Status routine for pending Online and Offline calls.
  56. PSET_RESOURCE_STATUS_ROUTINE g_SetResourceStatus = NULL;
  57. // Forward reference to our RESAPI function table.
  58. extern CLRES_FUNCTION_TABLE g_RSClusterFunctionTable;
  59. //
  60. // RSCluster resource read-write private properties.
  61. //
  62. RESUTIL_PROPERTY_ITEM
  63. RSClusterResourcePrivateProperties[] = {
  64. { 0 }
  65. };
  66. //
  67. // Function prototypes.
  68. //
  69. DWORD
  70. WINAPI
  71. Startup(
  72. IN LPCWSTR ResourceType,
  73. IN DWORD MinVersionSupported,
  74. IN DWORD MaxVersionSupported,
  75. IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  76. IN PLOG_EVENT_ROUTINE LogEvent,
  77. OUT PCLRES_FUNCTION_TABLE *FunctionTable
  78. );
  79. RESID
  80. WINAPI
  81. RSClusterOpen(
  82. IN LPCWSTR ResourceName,
  83. IN HKEY ResourceKey,
  84. IN RESOURCE_HANDLE ResourceHandle
  85. );
  86. VOID
  87. WINAPI
  88. RSClusterClose(
  89. IN RESID ResourceId
  90. );
  91. DWORD
  92. WINAPI
  93. RSClusterOnline(
  94. IN RESID ResourceId,
  95. IN OUT PHANDLE EventHandle
  96. );
  97. DWORD
  98. WINAPI
  99. RSClusterOnlineThread(
  100. PCLUS_WORKER WorkerPtr,
  101. IN PRSCLUSTER_RESOURCE ResourceEntry
  102. );
  103. DWORD
  104. WINAPI
  105. RSClusterOffline(
  106. IN RESID ResourceId
  107. );
  108. DWORD
  109. RSClusterOfflineThread(
  110. PCLUS_WORKER pWorker,
  111. IN PRSCLUSTER_RESOURCE ResourceEntry
  112. );
  113. VOID
  114. WINAPI
  115. RSClusterTerminate(
  116. IN RESID ResourceId
  117. );
  118. DWORD
  119. RSClusterDoTerminate(
  120. IN PRSCLUSTER_RESOURCE ResourceEntry
  121. );
  122. BOOL
  123. WINAPI
  124. RSClusterLooksAlive(
  125. IN RESID ResourceId
  126. );
  127. BOOL
  128. WINAPI
  129. RSClusterIsAlive(
  130. IN RESID ResourceId
  131. );
  132. BOOL
  133. RSClusterCheckIsAlive(
  134. IN PRSCLUSTER_RESOURCE ResourceEntry
  135. );
  136. DWORD
  137. WINAPI
  138. RSClusterResourceControl(
  139. IN RESID ResourceId,
  140. IN DWORD ControlCode,
  141. IN PVOID InBuffer,
  142. IN DWORD InBufferSize,
  143. OUT PVOID OutBuffer,
  144. IN DWORD OutBufferSize,
  145. OUT LPDWORD BytesReturned
  146. );
  147. BOOLEAN
  148. WINAPI
  149. DllMain(
  150. IN HINSTANCE DllHandle,
  151. IN DWORD Reason,
  152. IN LPVOID Reserved
  153. )
  154. /*++
  155. Routine Description:
  156. Main DLL entry point.
  157. Arguments:
  158. DllHandle - DLL instance handle.
  159. Reason - Reason for being called.
  160. Reserved - Reserved argument.
  161. Return Value:
  162. TRUE - Success.
  163. FALSE - Failure.
  164. --*/
  165. {
  166. switch( Reason ) {
  167. case DLL_PROCESS_ATTACH:
  168. DisableThreadLibraryCalls( DllHandle );
  169. break;
  170. case DLL_PROCESS_DETACH:
  171. break;
  172. }
  173. return(TRUE);
  174. } // DllMain
  175. DWORD
  176. WINAPI
  177. Startup(
  178. IN LPCWSTR ResourceType,
  179. IN DWORD MinVersionSupported,
  180. IN DWORD MaxVersionSupported,
  181. IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  182. IN PLOG_EVENT_ROUTINE LogEvent,
  183. OUT PCLRES_FUNCTION_TABLE *FunctionTable
  184. )
  185. /*++
  186. Routine Description:
  187. Startup the resource DLL. This routine verifies that at least one
  188. currently supported version of the resource DLL is between
  189. MinVersionSupported and MaxVersionSupported. If not, then the resource
  190. DLL should return ERROR_REVISION_MISMATCH.
  191. If more than one version of the resource DLL interface is supported by
  192. the resource DLL, then the highest version (up to MaxVersionSupported)
  193. should be returned as the resource DLL's interface. If the returned
  194. version is not within range, then startup fails.
  195. The ResourceType is passed in so that if the resource DLL supports more
  196. than one ResourceType, it can pass back the correct function table
  197. associated with the ResourceType.
  198. Arguments:
  199. ResourceType - The type of resource requesting a function table.
  200. MinVersionSupported - The minimum resource DLL interface version
  201. supported by the cluster software.
  202. MaxVersionSupported - The maximum resource DLL interface version
  203. supported by the cluster software.
  204. SetResourceStatus - Pointer to a routine that the resource DLL should
  205. call to update the state of a resource after the Online or Offline
  206. routine returns a status of ERROR_IO_PENDING.
  207. LogEvent - Pointer to a routine that handles the reporting of events
  208. from the resource DLL.
  209. FunctionTable - Returns a pointer to the function table defined for the
  210. version of the resource DLL interface returned by the resource DLL.
  211. Return Value:
  212. ERROR_SUCCESS - The operation was successful.
  213. ERROR_MOD_NOT_FOUND - The resource type is unknown by this DLL.
  214. ERROR_REVISION_MISMATCH - The version of the cluster service doesn't
  215. match the versrion of the DLL.
  216. Win32 error code - The operation failed.
  217. --*/
  218. {
  219. if ( (MinVersionSupported > CLRES_VERSION_V1_00) ||
  220. (MaxVersionSupported < CLRES_VERSION_V1_00) ) {
  221. return(ERROR_REVISION_MISMATCH);
  222. }
  223. if ( lstrcmpiW( ResourceType, RSCLUSTER_RESNAME ) != 0 ) {
  224. return(ERROR_MOD_NOT_FOUND);
  225. }
  226. if ( !g_LogEvent ) {
  227. g_LogEvent = LogEvent;
  228. g_SetResourceStatus = SetResourceStatus;
  229. }
  230. *FunctionTable = &g_RSClusterFunctionTable;
  231. return(ERROR_SUCCESS);
  232. } // Startup
  233. RESID
  234. WINAPI
  235. RSClusterOpen(
  236. IN LPCWSTR ResourceName,
  237. IN HKEY ResourceKey,
  238. IN RESOURCE_HANDLE ResourceHandle
  239. )
  240. /*++
  241. Routine Description:
  242. Open routine for RSCluster resources.
  243. Open the specified resource (create an instance of the resource).
  244. Allocate all structures necessary to bring the specified resource
  245. online.
  246. Arguments:
  247. ResourceName - Supplies the name of the resource to open.
  248. ResourceKey - Supplies handle to the resource's cluster configuration
  249. database key.
  250. ResourceHandle - A handle that is passed back to the resource monitor
  251. when the SetResourceStatus or LogEvent method is called. See the
  252. description of the SetResourceStatus and LogEvent methods on the
  253. RSClusterStatup routine. This handle should never be closed or used
  254. for any purpose other than passing it as an argument back to the
  255. Resource Monitor in the SetResourceStatus or LogEvent callback.
  256. Return Value:
  257. RESID of created resource.
  258. NULL on failure.
  259. --*/
  260. {
  261. DWORD status;
  262. DWORD disposition;
  263. RESID resid = 0;
  264. HKEY parametersKey = NULL;
  265. // how many do I need actually??
  266. HKEY resKey = NULL;
  267. PRSCLUSTER_RESOURCE resourceEntry = NULL;
  268. HCLUSTER hCluster;
  269. //
  270. // Open the Parameters registry key for this resource.
  271. //
  272. status = ClusterRegCreateKey( ResourceKey,
  273. L"Parameters",
  274. 0,
  275. KEY_ALL_ACCESS,
  276. NULL,
  277. &parametersKey,
  278. &disposition );
  279. if ( status != ERROR_SUCCESS ) {
  280. (g_LogEvent)(
  281. ResourceHandle,
  282. LOG_ERROR,
  283. L"Unable to open Parameters key. Error: %1!u!.\n",
  284. status );
  285. goto exit;
  286. }
  287. status = ClusterRegOpenKey( ResourceKey,
  288. L"",
  289. KEY_READ,
  290. &resKey);
  291. if (status != ERROR_SUCCESS) {
  292. (g_LogEvent)(ResourceHandle,
  293. LOG_ERROR,
  294. L"Unable to open resource key. Error: %1!u!.\n",
  295. status );
  296. goto error_exit;
  297. }
  298. if ( g_ScHandle == NULL ) {
  299. g_ScHandle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
  300. if ( g_ScHandle == NULL ) {
  301. status = GetLastError();
  302. (g_LogEvent)(
  303. ResourceHandle,
  304. LOG_ERROR,
  305. L"Failed to open service control manager, error %1!u!.\n",
  306. status);
  307. goto error_exit;
  308. }
  309. }
  310. resourceEntry = LocalAlloc( LMEM_FIXED, sizeof(RSCLUSTER_RESOURCE) );
  311. if ( resourceEntry == NULL ) {
  312. status = GetLastError();
  313. (g_LogEvent)(
  314. ResourceHandle,
  315. LOG_ERROR,
  316. L"Unable to allocate resource entry structure. Error: %1!u!.\n",
  317. status );
  318. goto exit;
  319. }
  320. ZeroMemory( resourceEntry, sizeof(RSCLUSTER_RESOURCE) );
  321. resourceEntry->ResId = (RESID)resourceEntry; // for validation
  322. resourceEntry->ResourceHandle = ResourceHandle;
  323. resourceEntry->ParametersKey = parametersKey;
  324. resourceEntry->State = ClusterResourceOffline;
  325. resourceEntry->ResourceKey = resKey;
  326. resourceEntry->hSem= NULL;
  327. resourceEntry->ResourceName = LocalAlloc( LMEM_FIXED, (lstrlenW( ResourceName ) + 1) * sizeof(WCHAR) );
  328. if ( resourceEntry->ResourceName == NULL ) {
  329. goto exit;
  330. }
  331. lstrcpyW( resourceEntry->ResourceName, ResourceName );
  332. resourceEntry->hSem=CreateSemaphore(NULL,0,1,L"RemoteStorageServer");
  333. status=GetLastError();
  334. if(resourceEntry->hSem)
  335. {
  336. if(status==ERROR_ALREADY_EXISTS)
  337. {
  338. (g_LogEvent)(
  339. ResourceHandle,
  340. LOG_ERROR,
  341. L"Remote Storage is controlled by another resource. Error: %2!u!.\n",status );
  342. CloseHandle(resourceEntry->hSem);
  343. resourceEntry->hSem = NULL;
  344. goto error_exit;
  345. }
  346. }
  347. else
  348. {
  349. (g_LogEvent)(
  350. ResourceHandle,
  351. LOG_ERROR,
  352. L"Unable to create semaphore for Remote Storage Server Service . Error: %2!u!.\n",status );
  353. goto error_exit;
  354. }
  355. status = ERROR_SUCCESS;
  356. hCluster = OpenCluster(NULL);
  357. if (hCluster == NULL) {
  358. status = GetLastError();
  359. (g_LogEvent)(
  360. ResourceHandle,
  361. LOG_ERROR,
  362. L"Failed to open cluster, error %1!u!.",
  363. status );
  364. goto error_exit;
  365. }
  366. resourceEntry->hResource = OpenClusterResource(hCluster, ResourceName);
  367. status = GetLastError();
  368. CloseCluster(hCluster);
  369. if ( resourceEntry->hResource == NULL ) {
  370. (g_LogEvent)(
  371. ResourceHandle,
  372. LOG_ERROR,
  373. L"Failed to open resource, error %1!u!.", status );
  374. goto error_exit;
  375. }
  376. resid = (RESID)resourceEntry;
  377. error_exit:
  378. exit:
  379. if ( resid == 0 ) {
  380. if ( parametersKey != NULL ) {
  381. ClusterRegCloseKey( parametersKey );
  382. }
  383. if ( resourceEntry != NULL ) {
  384. LocalFree( resourceEntry->ResourceName );
  385. LocalFree( resourceEntry );
  386. }
  387. }
  388. if ( status != ERROR_SUCCESS ) {
  389. SetLastError( status );
  390. }
  391. return(resid);
  392. } // RSClusterOpen
  393. VOID
  394. WINAPI
  395. RSClusterClose(
  396. IN RESID ResourceId
  397. )
  398. /*++
  399. Routine Description:
  400. Close routine for RSCluster resources.
  401. Close the specified resource and deallocate all structures, etc.,
  402. allocated in the Open call. If the resource is not in the offline state,
  403. then the resource should be taken offline (by calling Terminate) before
  404. the close operation is performed.
  405. Arguments:
  406. ResourceId - Supplies the RESID of the resource to close.
  407. Return Value:
  408. None.
  409. --*/
  410. {
  411. PRSCLUSTER_RESOURCE resourceEntry;
  412. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  413. if ( resourceEntry == NULL ) {
  414. DBG_PRINT( "RSCluster: Close request for a nonexistent resource id %p\n",
  415. ResourceId );
  416. return;
  417. }
  418. if ( resourceEntry->ResId != ResourceId ) {
  419. (g_LogEvent)(
  420. resourceEntry->ResourceHandle,
  421. LOG_ERROR,
  422. L"Close resource sanity check failed! ResourceId = %1!u!.\n",
  423. ResourceId );
  424. return;
  425. }
  426. #ifdef LOG_VERBOSE
  427. (g_LogEvent)(
  428. resourceEntry->ResourceHandle,
  429. LOG_INFORMATION,
  430. L"Close request.\n" );
  431. #endif
  432. if ( resourceEntry->ParametersKey ) {
  433. ClusterRegCloseKey( resourceEntry->ParametersKey );
  434. }
  435. RSClusterTerminate( ResourceId );
  436. ClusterRegCloseKey( resourceEntry->ParametersKey );
  437. ClusterRegCloseKey( resourceEntry->ResourceKey );
  438. CloseClusterResource( resourceEntry->hResource );
  439. CloseHandle(resourceEntry->hSem);
  440. LocalFree( resourceEntry->ResourceName );
  441. LocalFree( resourceEntry );
  442. } // RSClusterClose
  443. DWORD
  444. WINAPI
  445. RSClusterOnline(
  446. IN RESID ResourceId,
  447. IN OUT PHANDLE EventHandle
  448. )
  449. /*++
  450. Routine Description:
  451. Online routine for RSCluster resources.
  452. Bring the specified resource online (available for use). The resource
  453. DLL should attempt to arbitrate for the resource if it is present on a
  454. shared medium, like a shared SCSI bus.
  455. Arguments:
  456. ResourceId - Supplies the resource id for the resource to be brought
  457. online (available for use).
  458. EventHandle - Returns a signalable handle that is signaled when the
  459. resource DLL detects a failure on the resource. This argument is
  460. NULL on input, and the resource DLL returns NULL if asynchronous
  461. notification of failures is not supported, otherwise this must be
  462. the address of a handle that is signaled on resource failures.
  463. Return Value:
  464. ERROR_SUCCESS - The operation was successful, and the resource is now
  465. online.
  466. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  467. ERROR_RESOURCE_NOT_AVAILABLE - If the resource was arbitrated with some
  468. other systems and one of the other systems won the arbitration.
  469. ERROR_IO_PENDING - The request is pending, a thread has been activated
  470. to process the online request. The thread that is processing the
  471. online request will periodically report status by calling the
  472. SetResourceStatus callback method, until the resource is placed into
  473. the ClusterResourceOnline state (or the resource monitor decides to
  474. timeout the online request and Terminate the resource. This pending
  475. timeout value is settable and has a default value of 3 minutes.).
  476. Win32 error code - The operation failed.
  477. --*/
  478. {
  479. DWORD status;
  480. PRSCLUSTER_RESOURCE resourceEntry;
  481. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  482. if ( resourceEntry == NULL ) {
  483. DBG_PRINT( "RSCluster: Online request for a nonexistent resource id %p.\n",
  484. ResourceId );
  485. return(ERROR_RESOURCE_NOT_FOUND);
  486. }
  487. if ( resourceEntry->ResId != ResourceId ) {
  488. (g_LogEvent)(
  489. resourceEntry->ResourceHandle,
  490. LOG_ERROR,
  491. L"Online service sanity check failed! ResourceId = %1!u!.\n",
  492. ResourceId );
  493. return(ERROR_RESOURCE_NOT_FOUND);
  494. }
  495. #ifdef LOG_VERBOSE
  496. (g_LogEvent)(
  497. resourceEntry->ResourceHandle,
  498. LOG_INFORMATION,
  499. L"Online request.\n" );
  500. #endif
  501. resourceEntry->State = ClusterResourceOffline;
  502. ClusWorkerTerminate( &resourceEntry->OnlineThread );
  503. status = ClusWorkerCreate( &resourceEntry->OnlineThread,
  504. (PWORKER_START_ROUTINE)RSClusterOnlineThread,
  505. resourceEntry );
  506. if ( status != ERROR_SUCCESS ) {
  507. resourceEntry->State = ClusterResourceFailed;
  508. (g_LogEvent)(
  509. resourceEntry->ResourceHandle,
  510. LOG_ERROR,
  511. L"Online: Unable to start thread, status %1!u!.\n",
  512. status
  513. );
  514. } else {
  515. status = ERROR_IO_PENDING;
  516. }
  517. return(status);
  518. } // RSClusterOnline
  519. DWORD
  520. WINAPI
  521. RSClusterOnlineThread(
  522. PCLUS_WORKER WorkerPtr,
  523. IN PRSCLUSTER_RESOURCE ResourceEntry
  524. )
  525. /*++
  526. Routine Description:
  527. Worker function which brings a resource from the resource table online.
  528. This function is executed in a separate thread.
  529. Arguments:
  530. WorkerPtr - Supplies the worker structure
  531. ResourceEntry - A pointer to the RSCLUSTER_RESOURCE block for this resource.
  532. Returns:
  533. ERROR_SUCCESS - The operation completed successfully.
  534. Win32 error code - The operation failed.
  535. --*/
  536. {
  537. SERVICE_STATUS_PROCESS ServiceStatus;
  538. LPWSTR * serviceArgArray = NULL;
  539. DWORD serviceArgCount = 0;
  540. DWORD valueSize;
  541. LPVOID Environment = NULL;
  542. WCHAR * p;
  543. LPSERVICE_FAILURE_ACTIONS pSvcFailureActions = NULL;
  544. DWORD cbBytesNeeded, i;
  545. LPQUERY_SERVICE_CONFIG lpquerysvcconfig=NULL;
  546. HANDLE processToken = NULL;
  547. RESOURCE_STATUS resourceStatus;
  548. DWORD status = ERROR_SUCCESS;
  549. ResUtilInitializeResourceStatus( &resourceStatus );
  550. resourceStatus.ResourceState = ClusterResourceFailed;
  551. // resourceStatus.WaitHint = 0;
  552. resourceStatus.CheckPoint = 1;
  553. ResourceEntry->dwServicePid = 0;
  554. ResourceEntry->ServiceHandle = OpenService( g_ScHandle,
  555. RSCLUSTER_SVCNAME,
  556. SERVICE_ALL_ACCESS );
  557. if ( ResourceEntry->ServiceHandle == NULL ) {
  558. status = GetLastError();
  559. (g_LogEvent)(
  560. ResourceEntry->ResourceHandle,
  561. LOG_ERROR,
  562. L"Failed to open service, error = %1!u!.\n",
  563. status );
  564. goto error_exit;
  565. }
  566. valueSize = sizeof(QUERY_SERVICE_CONFIG);
  567. AllocSvcConfig:
  568. lpquerysvcconfig=(LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_FIXED, valueSize);
  569. if(lpquerysvcconfig==NULL){
  570. status = GetLastError();
  571. (g_LogEvent)(
  572. ResourceEntry->ResourceHandle,
  573. LOG_ERROR,
  574. L"Remote Storage Server: Failed to allocate memory for query_service_config, error = %1!u!.\n",
  575. status );
  576. goto error_exit;
  577. }
  578. if (!QueryServiceConfig(ResourceEntry->ServiceHandle,
  579. lpquerysvcconfig,
  580. valueSize,
  581. &cbBytesNeeded))
  582. {
  583. status=GetLastError();
  584. if (status != ERROR_INSUFFICIENT_BUFFER){
  585. (g_LogEvent)(ResourceEntry->ResourceHandle,
  586. LOG_ERROR,
  587. L"Remote Storage Server: Failed to query service configuration, error= %1!u!.\n",
  588. status );
  589. goto error_exit;
  590. }
  591. status=ERROR_SUCCESS;
  592. LocalFree(lpquerysvcconfig);
  593. lpquerysvcconfig=NULL;
  594. valueSize = cbBytesNeeded;
  595. goto AllocSvcConfig;
  596. }
  597. if (lpquerysvcconfig->dwStartType == SERVICE_DISABLED)
  598. {
  599. (g_LogEvent)(
  600. ResourceEntry->ResourceHandle,
  601. LOG_ERROR,
  602. L"Remote Storage Server: the service is DISABLED\n");
  603. status=ERROR_SERVICE_DISABLED;
  604. goto error_exit;
  605. }
  606. ChangeServiceConfig( ResourceEntry->ServiceHandle,
  607. SERVICE_NO_CHANGE,
  608. SERVICE_DEMAND_START, // Manual start
  609. SERVICE_NO_CHANGE,
  610. NULL,
  611. NULL,
  612. NULL,
  613. NULL,
  614. NULL,
  615. NULL,
  616. NULL );
  617. if (!(QueryServiceConfig2(ResourceEntry->ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS,
  618. (LPBYTE)&valueSize, sizeof(DWORD), &cbBytesNeeded)))
  619. {
  620. status = GetLastError();
  621. if (status != ERROR_INSUFFICIENT_BUFFER)
  622. {
  623. (g_LogEvent)(
  624. ResourceEntry->ResourceHandle,
  625. LOG_ERROR,
  626. L"Remote Storage Server: Failed to query service configuration for size, error= %1!u!.\n",
  627. status );
  628. goto error_exit;
  629. }
  630. else
  631. status = ERROR_SUCCESS;
  632. }
  633. pSvcFailureActions = (LPSERVICE_FAILURE_ACTIONS)LocalAlloc(LMEM_FIXED, cbBytesNeeded);
  634. if ( pSvcFailureActions == NULL ) {
  635. status = GetLastError();
  636. (g_LogEvent)(
  637. ResourceEntry->ResourceHandle,
  638. LOG_ERROR,
  639. L"Remote Storage Server: Failed to allocate memory, error = %1!u!.\n",
  640. status );
  641. goto error_exit;
  642. }
  643. if (!(QueryServiceConfig2(ResourceEntry->ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS,
  644. (LPBYTE)pSvcFailureActions, cbBytesNeeded, &cbBytesNeeded)))
  645. {
  646. (g_LogEvent)(
  647. ResourceEntry->ResourceHandle,
  648. LOG_ERROR,
  649. L"Remote Storage Server: Failed to query service configuration, error = %1!u!.\n",
  650. status );
  651. goto error_exit;
  652. }
  653. for (i=0; i<pSvcFailureActions->cActions;i++)
  654. {
  655. if (pSvcFailureActions->lpsaActions[i].Type == SC_ACTION_RESTART)
  656. pSvcFailureActions->lpsaActions[i].Type = SC_ACTION_NONE;
  657. }
  658. ChangeServiceConfig2(ResourceEntry->ServiceHandle,
  659. SERVICE_CONFIG_FAILURE_ACTIONS,
  660. pSvcFailureActions);
  661. if ( 0 )
  662. {
  663. Environment = ResUtilGetEnvironmentWithNetName( ResourceEntry->hResource );
  664. }
  665. else
  666. {
  667. BOOL success;
  668. OpenProcessToken( GetCurrentProcess(), MAXIMUM_ALLOWED, &processToken );
  669. success = CreateEnvironmentBlock(&Environment, processToken, FALSE );
  670. if ( processToken != NULL ) {
  671. CloseHandle( processToken );
  672. }
  673. if ( !success ) {
  674. status = GetLastError();
  675. goto error_exit;
  676. }
  677. }
  678. if (Environment != NULL) {
  679. HKEY ServicesKey;
  680. HKEY hKey;
  681. p = (WCHAR *)Environment;
  682. while (*p) {
  683. while (*p++) {
  684. }
  685. }
  686. valueSize = (DWORD)((PUCHAR)p - (PUCHAR)Environment) +
  687. sizeof(WCHAR);
  688. status = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  689. SERVICES_ROOT,
  690. 0,
  691. KEY_READ,
  692. &ServicesKey );
  693. if (status != ERROR_SUCCESS) {
  694. (g_LogEvent)(
  695. ResourceEntry->ResourceHandle,
  696. LOG_ERROR,
  697. L"Failed to open services key, error = %1!u!.\n",
  698. status );
  699. goto error_exit;
  700. }
  701. status = RegOpenKeyExW( ServicesKey,
  702. RSCLUSTER_SVCNAME,
  703. 0,
  704. KEY_READ | KEY_WRITE,
  705. &hKey );
  706. RegCloseKey(ServicesKey);
  707. if (status != ERROR_SUCCESS) {
  708. (g_LogEvent)(
  709. ResourceEntry->ResourceHandle,
  710. LOG_ERROR,
  711. L"Failed to open service key, error = %1!u!.\n",
  712. status );
  713. goto error_exit;
  714. }
  715. status = RegSetValueExW( hKey,
  716. L"Environment",
  717. 0,
  718. REG_MULTI_SZ,
  719. Environment,
  720. valueSize );
  721. RegCloseKey(hKey);
  722. if (status != ERROR_SUCCESS) {
  723. (g_LogEvent)(
  724. ResourceEntry->ResourceHandle,
  725. LOG_ERROR,
  726. L"Failed to set service environment value, error = %1!u!.\n",
  727. status );
  728. goto error_exit;
  729. }
  730. }
  731. if ( !StartServiceW( ResourceEntry->ServiceHandle,
  732. serviceArgCount,
  733. serviceArgArray ) )
  734. {
  735. status = GetLastError();
  736. if (status != ERROR_SERVICE_ALREADY_RUNNING) {
  737. (g_LogEvent)(ResourceEntry->ResourceHandle,
  738. LOG_ERROR,
  739. L"Failed to start service. Error: %1!u!.\n",
  740. status );
  741. status = ERROR_SERVICE_NEVER_STARTED;
  742. goto error_exit;
  743. }
  744. // add code to stop the service that is running
  745. // and start the service again..
  746. }
  747. while (!ClusWorkerCheckTerminate(WorkerPtr)) {
  748. if (!QueryServiceStatusEx(
  749. ResourceEntry->ServiceHandle,
  750. SC_STATUS_PROCESS_INFO, (LPBYTE)&ServiceStatus,
  751. sizeof(SERVICE_STATUS_PROCESS), &cbBytesNeeded ) )
  752. {
  753. status = GetLastError();
  754. (g_LogEvent)(
  755. ResourceEntry->ResourceHandle,
  756. LOG_ERROR,
  757. L"Query Service Status failed %1!u!.\n",
  758. status );
  759. goto error_exit;
  760. }
  761. if ( ServiceStatus.dwCurrentState != SERVICE_START_PENDING ) {
  762. break;
  763. }
  764. Sleep(250);
  765. }
  766. if (ClusWorkerCheckTerminate(WorkerPtr)) {
  767. goto error_exit;
  768. }
  769. if ( ServiceStatus.dwCurrentState != SERVICE_RUNNING ) {
  770. (g_LogEvent)(
  771. ResourceEntry->ResourceHandle,
  772. LOG_ERROR,
  773. L"Failed to start service. Error: %1!u!.\n",
  774. ERROR_SERVICE_NEVER_STARTED );
  775. status = ERROR_SERVICE_NEVER_STARTED;
  776. goto error_exit;
  777. }
  778. resourceStatus.ResourceState = ClusterResourceOnline;
  779. if (!(ServiceStatus.dwServiceFlags & SERVICE_RUNS_IN_SYSTEM_PROCESS)) {
  780. ResourceEntry->dwServicePid = ServiceStatus.dwProcessId;
  781. }
  782. (g_LogEvent)(
  783. ResourceEntry->ResourceHandle,
  784. LOG_INFORMATION,
  785. L"Service is now on line.\n" );
  786. error_exit:
  787. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  788. &resourceStatus );
  789. if ( resourceStatus.ResourceState == ClusterResourceOnline ) {
  790. ResourceEntry->Online = TRUE;
  791. } else {
  792. ResourceEntry->Online = FALSE;
  793. }
  794. // more setting here to ensure no problems
  795. ResourceEntry->State = resourceStatus.ResourceState;
  796. //cleanup
  797. if (pSvcFailureActions)
  798. LocalFree(pSvcFailureActions);
  799. if (lpquerysvcconfig)
  800. LocalFree(lpquerysvcconfig);
  801. LocalFree( serviceArgArray );
  802. if (Environment != NULL) {
  803. DestroyEnvironmentBlock(Environment);
  804. }
  805. return(status);
  806. } // RSClusterOnlineThread
  807. DWORD
  808. WINAPI
  809. RSClusterOffline(
  810. IN RESID ResourceId
  811. )
  812. /*++
  813. Routine Description:
  814. Offline routine for RSCluster resources.
  815. Take the specified resource offline gracefully (unavailable for use).
  816. Wait for any cleanup operations to complete before returning.
  817. Arguments:
  818. ResourceId - Supplies the resource id for the resource to be shutdown
  819. gracefully.
  820. Return Value:
  821. ERROR_SUCCESS - The request completed successfully and the resource is
  822. offline.
  823. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  824. ERROR_IO_PENDING - The request is still pending, a thread has been
  825. activated to process the offline request. The thread that is
  826. processing the offline will periodically report status by calling
  827. the SetResourceStatus callback method, until the resource is placed
  828. into the ClusterResourceOffline state (or the resource monitor decides
  829. to timeout the offline request and Terminate the resource).
  830. Win32 error code - Will cause the resource monitor to log an event and
  831. call the Terminate routine.
  832. --*/
  833. {
  834. // extra code here
  835. DWORD status;
  836. PRSCLUSTER_RESOURCE resourceEntry;
  837. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  838. if ( resourceEntry == NULL ) {
  839. DBG_PRINT( "RSCluster: Offline request for a nonexistent resource id %p\n",
  840. ResourceId );
  841. return(ERROR_RESOURCE_NOT_FOUND);
  842. }
  843. if ( resourceEntry->ResId != ResourceId ) {
  844. (g_LogEvent)(
  845. resourceEntry->ResourceHandle,
  846. LOG_ERROR,
  847. L"Offline resource sanity check failed! ResourceId = %1!u!.\n",
  848. ResourceId );
  849. return(ERROR_RESOURCE_NOT_FOUND);
  850. }
  851. #ifdef LOG_VERBOSE
  852. (g_LogEvent)(
  853. resourceEntry->ResourceHandle,
  854. LOG_INFORMATION,
  855. L"Offline request.\n" );
  856. #endif
  857. ClusWorkerTerminate( &resourceEntry->PendingThread );
  858. status = ClusWorkerCreate( &resourceEntry->PendingThread,
  859. (PWORKER_START_ROUTINE)RSClusterOfflineThread,
  860. resourceEntry );
  861. if ( status == ERROR_SUCCESS ) {
  862. status = ERROR_IO_PENDING;
  863. }
  864. return(status);
  865. } // RSClusterOffline
  866. DWORD
  867. RSClusterOfflineThread(
  868. PCLUS_WORKER pWorker,
  869. IN PRSCLUSTER_RESOURCE ResourceEntry
  870. )
  871. /*++
  872. Routine Description:
  873. Brings remote storage service resource offline
  874. Arguments:
  875. Worker - Supplies the worker structure
  876. Context - A pointer to the DiskInfo block for this resource.
  877. Returns:
  878. ERROR_SUCCESS if successful.
  879. Win32 error code on failure.
  880. --*/
  881. {
  882. RESOURCE_STATUS resourceStatus;
  883. DWORD retryTick = 300; // 300 msec at a time
  884. DWORD status = ERROR_SUCCESS;
  885. BOOL didStop = FALSE;
  886. SERVICE_STATUS ServiceStatus;
  887. ResUtilInitializeResourceStatus( &resourceStatus );
  888. resourceStatus.ResourceState = ClusterResourceFailed;
  889. //resourceStatus.WaitHint = 0;
  890. resourceStatus.CheckPoint = 1;
  891. if ( ResourceEntry->ServiceHandle == NULL )
  892. {
  893. resourceStatus.ResourceState = ClusterResourceOffline;
  894. goto FnExit;
  895. }
  896. while (!ClusWorkerCheckTerminate(pWorker)) {
  897. status = (ControlService(
  898. ResourceEntry->ServiceHandle,
  899. (didStop
  900. ? SERVICE_CONTROL_INTERROGATE
  901. : SERVICE_CONTROL_STOP),
  902. &ServiceStatus )
  903. ? NO_ERROR
  904. : GetLastError());
  905. if (status == NO_ERROR) {
  906. didStop = TRUE;
  907. if (ServiceStatus.dwCurrentState == SERVICE_STOPPED) {
  908. (g_LogEvent)(
  909. ResourceEntry->ResourceHandle,
  910. LOG_INFORMATION,
  911. L"Service stopped.\n" );
  912. //set the status
  913. ResourceEntry->Online = FALSE;
  914. resourceStatus.ResourceState = ClusterResourceOffline;
  915. CloseServiceHandle( ResourceEntry->ServiceHandle );
  916. ResourceEntry->ServiceHandle = NULL;
  917. ResourceEntry->dwServicePid = 0;
  918. (g_LogEvent)(
  919. ResourceEntry->ResourceHandle,
  920. LOG_INFORMATION,
  921. L"Service is now offline.\n" );
  922. break;
  923. }
  924. }
  925. if (status == ERROR_EXCEPTION_IN_SERVICE ||
  926. status == ERROR_PROCESS_ABORTED ||
  927. status == ERROR_SERVICE_NOT_ACTIVE) {
  928. (g_LogEvent)(
  929. ResourceEntry->ResourceHandle,
  930. LOG_INFORMATION,
  931. L"Service died or not active any more; status = %1!u!.\n",
  932. status);
  933. ResourceEntry->Online = FALSE;
  934. resourceStatus.ResourceState = ClusterResourceOffline;
  935. CloseServiceHandle( ResourceEntry->ServiceHandle );
  936. ResourceEntry->ServiceHandle = NULL;
  937. ResourceEntry->dwServicePid = 0;
  938. (g_LogEvent)(
  939. ResourceEntry->ResourceHandle,
  940. LOG_INFORMATION,
  941. L"Service is now offline.\n" );
  942. break;
  943. }
  944. (g_LogEvent)(
  945. ResourceEntry->ResourceHandle,
  946. LOG_INFORMATION,
  947. L"Offline: retrying...\n" );
  948. Sleep(retryTick);
  949. }
  950. FnExit:
  951. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  952. &resourceStatus );
  953. return(status);
  954. } // RSClusterOfflineThread
  955. VOID
  956. WINAPI
  957. RSClusterTerminate(
  958. IN RESID ResourceId
  959. )
  960. /*++
  961. Routine Description:
  962. Terminate routine for RSCluster resources.
  963. Take the specified resource offline immediately (the resource is
  964. unavailable for use).
  965. Arguments:
  966. ResourceId - Supplies the resource id for the resource to be brought
  967. offline.
  968. Return Value:
  969. None.
  970. --*/
  971. {
  972. // extra code here
  973. PRSCLUSTER_RESOURCE resourceEntry;
  974. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  975. if ( resourceEntry == NULL ) {
  976. DBG_PRINT( "RSCluster: Terminate request for a nonexistent resource id %p\n",
  977. ResourceId );
  978. return;
  979. }
  980. if ( resourceEntry->ResId != ResourceId ) {
  981. (g_LogEvent)(
  982. resourceEntry->ResourceHandle,
  983. LOG_ERROR,
  984. L"Terminate resource sanity check failed! ResourceId = %1!u!.\n",
  985. ResourceId );
  986. return;
  987. }
  988. #ifdef LOG_VERBOSE
  989. (g_LogEvent)(
  990. resourceEntry->ResourceHandle,
  991. LOG_INFORMATION,
  992. L"Terminate request.\n" );
  993. #endif
  994. RSClusterDoTerminate( resourceEntry );
  995. resourceEntry->State = ClusterResourceOffline;
  996. } // RSClusterTerminate
  997. DWORD
  998. RSClusterDoTerminate(
  999. IN PRSCLUSTER_RESOURCE resourceEntry
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. Do the actual Terminate work for RSCluster resources.
  1004. Arguments:
  1005. ResourceEntry - Supplies resource entry for resource to be terminated
  1006. Return Value:
  1007. ERROR_SUCCESS - The request completed successfully and the resource is
  1008. offline.
  1009. Win32 error code - Will cause the resource monitor to log an event and
  1010. call the Terminate routine.
  1011. --*/
  1012. {
  1013. DWORD status = ERROR_SUCCESS;
  1014. SERVICE_STATUS ServiceStatus;
  1015. ClusWorkerTerminate( &resourceEntry->OnlineThread );
  1016. ClusWorkerTerminate( &resourceEntry->PendingThread );
  1017. if ( resourceEntry->ServiceHandle != NULL )
  1018. {
  1019. DWORD dwRetryCount= 100;
  1020. BOOL didStop = FALSE;
  1021. DWORD dwRetryTick = 300; // 300 msec at a time
  1022. DWORD dwStatus;
  1023. while (dwRetryCount--)
  1024. {
  1025. (g_LogEvent)(
  1026. resourceEntry->ResourceHandle,
  1027. LOG_INFORMATION,
  1028. L"RSClusterTerminate : calling SCM\n" );
  1029. dwStatus = (ControlService(
  1030. resourceEntry->ServiceHandle,
  1031. (didStop
  1032. ? SERVICE_CONTROL_INTERROGATE
  1033. : SERVICE_CONTROL_STOP),
  1034. &ServiceStatus )
  1035. ? NO_ERROR
  1036. : GetLastError());
  1037. if (dwStatus == NO_ERROR)
  1038. {
  1039. didStop = TRUE;
  1040. if (ServiceStatus.dwCurrentState == SERVICE_STOPPED)
  1041. {
  1042. (g_LogEvent)(
  1043. resourceEntry->ResourceHandle,
  1044. LOG_INFORMATION,
  1045. L"Service stopped.\n" );
  1046. //set the status
  1047. resourceEntry->Online = FALSE;
  1048. resourceEntry->dwServicePid = 0;
  1049. break;
  1050. }
  1051. }
  1052. if (dwStatus == ERROR_EXCEPTION_IN_SERVICE ||
  1053. dwStatus == ERROR_PROCESS_ABORTED ||
  1054. dwStatus == ERROR_SERVICE_NOT_ACTIVE)
  1055. {
  1056. (g_LogEvent)(
  1057. resourceEntry->ResourceHandle,
  1058. LOG_INFORMATION,
  1059. L"Service died; status = %1!u!.\n",
  1060. dwStatus);
  1061. //set the status
  1062. resourceEntry->Online = FALSE;
  1063. resourceEntry->dwServicePid = 0;
  1064. break;
  1065. }
  1066. (g_LogEvent)(
  1067. resourceEntry->ResourceHandle,
  1068. LOG_INFORMATION,
  1069. L"RSClusterTerminate: retrying...\n" );
  1070. Sleep(dwRetryTick);
  1071. }
  1072. if (resourceEntry->dwServicePid)
  1073. {
  1074. HANDLE hSvcProcess = NULL;
  1075. hSvcProcess = OpenProcess(PROCESS_TERMINATE,
  1076. FALSE, resourceEntry->dwServicePid);
  1077. if (hSvcProcess)
  1078. {
  1079. (g_LogEvent)(
  1080. resourceEntry->ResourceHandle,
  1081. LOG_INFORMATION,
  1082. L"RSClusterTerminate: terminating processid=%1!u!\n",
  1083. resourceEntry->dwServicePid);
  1084. TerminateProcess(hSvcProcess, 0);
  1085. CloseHandle(hSvcProcess);
  1086. }
  1087. }
  1088. CloseServiceHandle( resourceEntry->ServiceHandle );
  1089. resourceEntry->ServiceHandle = NULL;
  1090. resourceEntry->dwServicePid = 0;
  1091. }
  1092. resourceEntry->Online = FALSE;
  1093. // //
  1094. resourceEntry->State = ClusterResourceOffline;
  1095. /*
  1096. if ( status == ERROR_SUCCESS ) {
  1097. ResourceEntry->State = ClusterResourceOffline;
  1098. }
  1099. return(status);
  1100. */
  1101. return(ERROR_SUCCESS);
  1102. } // RSClusterDoTerminate
  1103. BOOL
  1104. WINAPI
  1105. RSClusterLooksAlive(
  1106. IN RESID ResourceId
  1107. )
  1108. /*++
  1109. Routine Description:
  1110. LooksAlive routine for RSCluster resources.
  1111. Perform a quick check to determine if the specified resource is probably
  1112. online (available for use). This call should not block for more than
  1113. 300 ms, preferably less than 50 ms.
  1114. Arguments:
  1115. ResourceId - Supplies the resource id for the resource to polled.
  1116. Return Value:
  1117. TRUE - The specified resource is probably online and available for use.
  1118. FALSE - The specified resource is not functioning normally.
  1119. --*/
  1120. {
  1121. PRSCLUSTER_RESOURCE resourceEntry;
  1122. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  1123. if ( resourceEntry == NULL ) {
  1124. DBG_PRINT("RSCluster: LooksAlive request for a nonexistent resource id %p\n",
  1125. ResourceId );
  1126. return(FALSE);
  1127. }
  1128. if ( resourceEntry->ResId != ResourceId ) {
  1129. (g_LogEvent)(
  1130. resourceEntry->ResourceHandle,
  1131. LOG_ERROR,
  1132. L"LooksAlive sanity check failed! ResourceId = %1!u!.\n",
  1133. ResourceId );
  1134. return(FALSE);
  1135. }
  1136. #ifdef LOG_VERBOSE
  1137. (g_LogEvent)(
  1138. resourceEntry->ResourceHandle,
  1139. LOG_INFORMATION,
  1140. L"LooksAlive request.\n" );
  1141. #endif
  1142. //
  1143. return(RSClusterCheckIsAlive( resourceEntry ));
  1144. } // RSClusterLooksAlive
  1145. BOOL
  1146. WINAPI
  1147. RSClusterIsAlive(
  1148. IN RESID ResourceId
  1149. )
  1150. /*++
  1151. Routine Description:
  1152. IsAlive routine for RSCluster resources.
  1153. Perform a thorough check to determine if the specified resource is online
  1154. (available for use). This call should not block for more than 400 ms,
  1155. preferably less than 100 ms.
  1156. Arguments:
  1157. ResourceId - Supplies the resource id for the resource to polled.
  1158. Return Value:
  1159. TRUE - The specified resource is online and functioning normally.
  1160. FALSE - The specified resource is not functioning normally.
  1161. --*/
  1162. {
  1163. PRSCLUSTER_RESOURCE resourceEntry;
  1164. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  1165. if ( resourceEntry == NULL ) {
  1166. DBG_PRINT("RSCluster: IsAlive request for a nonexistent resource id %p\n",
  1167. ResourceId );
  1168. return(FALSE);
  1169. }
  1170. if ( resourceEntry->ResId != ResourceId ) {
  1171. (g_LogEvent)(
  1172. resourceEntry->ResourceHandle,
  1173. LOG_ERROR,
  1174. L"IsAlive sanity check failed! ResourceId = %1!u!.\n",
  1175. ResourceId );
  1176. return(FALSE);
  1177. }
  1178. #ifdef LOG_VERBOSE
  1179. (g_LogEvent)(
  1180. resourceEntry->ResourceHandle,
  1181. LOG_INFORMATION,
  1182. L"IsAlive request.\n" );
  1183. #endif
  1184. return(RSClusterCheckIsAlive( resourceEntry ));
  1185. } // RSClusterIsAlive
  1186. BOOL
  1187. RSClusterCheckIsAlive(
  1188. IN PRSCLUSTER_RESOURCE resourceEntry
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. Check to see if the resource is alive for RSCluster resources.
  1193. Arguments:
  1194. ResourceEntry - Supplies the resource entry for the resource to polled.
  1195. Return Value:
  1196. TRUE - The specified resource is online and functioning normally.
  1197. FALSE - The specified resource is not functioning normally.
  1198. --*/
  1199. {
  1200. SERVICE_STATUS ServiceStatus;
  1201. DWORD status = TRUE;
  1202. if ( !QueryServiceStatus( resourceEntry->ServiceHandle,
  1203. &ServiceStatus ) ) {
  1204. (g_LogEvent)(
  1205. resourceEntry->ResourceHandle,
  1206. LOG_ERROR,
  1207. L"Query Service Status failed %1!u!.\n",
  1208. GetLastError() );
  1209. return(FALSE);
  1210. }
  1211. if ( (ServiceStatus.dwCurrentState != SERVICE_RUNNING) &&
  1212. (ServiceStatus.dwCurrentState != SERVICE_START_PENDING) ) {
  1213. status = FALSE;
  1214. }
  1215. if (!status) {
  1216. (g_LogEvent)(
  1217. resourceEntry->ResourceHandle,
  1218. LOG_ERROR,
  1219. L"Failed the IsAlive test. Current State is %1!u!.\n",
  1220. ServiceStatus.dwCurrentState );
  1221. }
  1222. return(status);
  1223. } // RSClusterCheckIsAlive
  1224. DWORD
  1225. WINAPI
  1226. RSClusterResourceControl(
  1227. IN RESID ResourceId,
  1228. IN DWORD ControlCode,
  1229. IN PVOID InBuffer,
  1230. IN DWORD InBufferSize,
  1231. OUT PVOID OutBuffer,
  1232. IN DWORD OutBufferSize,
  1233. OUT LPDWORD BytesReturned
  1234. )
  1235. /*++
  1236. Routine Description:
  1237. ResourceControl routine for RSCluster resources.
  1238. Perform the control request specified by ControlCode on the specified
  1239. resource.
  1240. Arguments:
  1241. ResourceId - Supplies the resource id for the specific resource.
  1242. ControlCode - Supplies the control code that defines the action
  1243. to be performed.
  1244. InBuffer - Supplies a pointer to a buffer containing input data.
  1245. InBufferSize - Supplies the size, in bytes, of the data pointed
  1246. to by InBuffer.
  1247. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1248. OutBufferSize - Supplies the size, in bytes, of the available space
  1249. pointed to by OutBuffer.
  1250. BytesReturned - Returns the number of bytes of OutBuffer actually
  1251. filled in by the resource. If OutBuffer is too small, BytesReturned
  1252. contains the total number of bytes for the operation to succeed.
  1253. Return Value:
  1254. ERROR_SUCCESS - The function completed successfully.
  1255. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  1256. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1257. In some cases, this allows the cluster software to perform the work.
  1258. Win32 error code - The function failed.
  1259. --*/
  1260. {
  1261. DWORD status;
  1262. PRSCLUSTER_RESOURCE resourceEntry;
  1263. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  1264. if ( resourceEntry == NULL ) {
  1265. DBG_PRINT("RSCluster: ResourceControl request for a nonexistent resource id %p\n",
  1266. ResourceId );
  1267. return(ERROR_RESOURCE_NOT_FOUND);
  1268. }
  1269. if ( resourceEntry->ResId != ResourceId ) {
  1270. (g_LogEvent)(
  1271. resourceEntry->ResourceHandle,
  1272. LOG_ERROR,
  1273. L"ResourceControl sanity check failed! ResourceId = %1!u!.\n",
  1274. ResourceId );
  1275. return(ERROR_RESOURCE_NOT_FOUND);
  1276. }
  1277. switch ( ControlCode ) {
  1278. case CLUSCTL_RESOURCE_UNKNOWN:
  1279. *BytesReturned = 0;
  1280. status = ERROR_SUCCESS;
  1281. break;
  1282. default:
  1283. status = ERROR_INVALID_FUNCTION;
  1284. break;
  1285. }
  1286. return(status);
  1287. } // RSClusterResourceControl
  1288. //***********************************************************
  1289. //
  1290. // Define Function Table
  1291. //
  1292. //***********************************************************
  1293. CLRES_V1_FUNCTION_TABLE( g_RSClusterFunctionTable, // Name
  1294. CLRES_VERSION_V1_00, // Version
  1295. RSCluster, // Prefix
  1296. NULL, // Arbitrate
  1297. NULL, // Release
  1298. RSClusterResourceControl, // ResControl
  1299. NULL); // ResTypeControl