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.

1267 lines
31 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. gensvc.c
  5. Abstract:
  6. Resource DLL to control and monitor NT services.
  7. Author:
  8. Robs 3/28/96, based on RodGa's generic resource dll
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. //
  13. #include "nt.h"
  14. #include "ntrtl.h"
  15. #include "nturtl.h"
  16. #include "windows.h"
  17. #include "clusapi.h"
  18. #include "clusudef.h"
  19. #include "resapi.h"
  20. #include "bosvc.h"
  21. #include "xchgclus.h"
  22. #include "xchgdat.h"
  23. extern PLOG_EVENT_ROUTINE g_LogEvent;
  24. extern PSET_RESOURCE_STATUS_ROUTINE g_SetResourceStatus;
  25. #define DBG_PRINT printf
  26. //
  27. // Global Data
  28. //
  29. // Handle to service controller, set by the first create resource call.
  30. static SC_HANDLE g_ScHandle = NULL;
  31. //
  32. // Forward routines
  33. //
  34. DWORD
  35. XchgOnlineThread(
  36. IN PCLUS_WORKER pWorker,
  37. IN PCOMMON_RESOURCE ResourceEntry
  38. );
  39. BOOL
  40. XchgVerifyService(
  41. IN RESID ResourceId,
  42. IN BOOL IsAliveFlag
  43. );
  44. HANDLE
  45. XchgOpenSvc(
  46. IN SERVICE_NAME ServiceName,
  47. IN PCOMMON_RESOURCE ResourceEntry
  48. );
  49. DWORD
  50. XchgSetSvcEnv(
  51. IN HKEY ServicesKey,
  52. IN SERVICE_NAME ServiceName,
  53. IN LPVOID Environment,
  54. IN DWORD ValueSize,
  55. IN PCOMMON_RESOURCE ResourceEntry
  56. );
  57. #ifdef COMMON_ONLINE_THREAD
  58. #define COMMON_ONLINE_THREAD_ROUTINE COMMON_ONLINE_THREAD
  59. #else
  60. #define COMMON_ONLINE_THREAD_ROUTINE XchgOnlineThread
  61. #endif
  62. //
  63. // Local Routines
  64. //
  65. #ifndef COMMON_ONLINE_THREAD
  66. DWORD
  67. XchgOnlineThread(
  68. IN PCLUS_WORKER pWorker,
  69. IN PCOMMON_RESOURCE ResourceEntry
  70. )
  71. /*++
  72. Routine Description:
  73. Brings a disk resource online.
  74. Arguments:
  75. Worker - Supplies the worker structure
  76. Context - A pointer to the DiskInfo block for this resource.
  77. Returns:
  78. ERROR_SUCCESS if successful.
  79. Win32 error code on failure.
  80. --*/
  81. {
  82. SERVICE_STATUS ServiceStatus;
  83. DWORD status = ERROR_SUCCESS;
  84. DWORD numchars;
  85. RESOURCE_STATUS resourceStatus;
  86. HANDLE serviceHandle;
  87. DWORD valueSize;
  88. WCHAR * p;
  89. LPVOID Environment = NULL;
  90. HKEY ServicesKey;
  91. DWORD dwSvcCnt;
  92. DWORD dwDependencyCnt;
  93. PSERVICE_INFO pSvcInfo;
  94. ResUtilInitializeResourceStatus( &resourceStatus );
  95. resourceStatus.ResourceState = ClusterResourceFailed;
  96. //resourceStatus.WaitHint = 0;
  97. resourceStatus.CheckPoint = 1;
  98. #if ENVIRONMENT
  99. //
  100. // Create the new environment with the simulated net name when the
  101. // services queries GetComputerName.
  102. //
  103. Environment = ResUtilGetEnvironmentWithNetName( ResourceEntry->hResource );
  104. if (!Environment)
  105. {
  106. status = GetLastError();
  107. (g_LogEvent)(
  108. ResourceEntry->ResourceHandle,
  109. LOG_ERROR,
  110. L"XchgOnlineThread:Failed to get environment with netname, error = %1!u!.\n",
  111. status );
  112. goto error_exit;
  113. }
  114. //
  115. // Compute the size of the environment. We are looking for
  116. // the double NULL terminator that ends the environment block.
  117. //
  118. p = (WCHAR *)Environment;
  119. while (*p) {
  120. while (*p++) {
  121. }
  122. }
  123. valueSize = (DWORD)((PUCHAR)p - (PUCHAR)Environment) + sizeof(WCHAR);
  124. //
  125. // Set the environment value in the service's registry key.
  126. //
  127. status = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  128. LOCAL_SERVICES,
  129. 0,
  130. KEY_READ,
  131. &ServicesKey );
  132. if (status != ERROR_SUCCESS) {
  133. (g_LogEvent)(
  134. ResourceEntry->ResourceHandle,
  135. LOG_ERROR,
  136. L"XchgOnlineThread:Failed to open services key, error = %1!u!.\n",
  137. status );
  138. goto error_exit;
  139. }
  140. for (dwSvcCnt=0; dwSvcCnt< ServiceInfoList.dwMaxSvcCnt; dwSvcCnt++)
  141. {
  142. pSvcInfo = &ServiceInfoList.SvcInfo[dwSvcCnt];
  143. status = XchgSetSvcEnv(ServicesKey, pSvcInfo->snSvcName,
  144. Environment, valueSize, ResourceEntry);
  145. if (status != ERROR_SUCCESS)
  146. goto error_exit;
  147. for (dwDependencyCnt=0; dwDependencyCnt < pSvcInfo->dwDependencyCnt; dwDependencyCnt++)
  148. {
  149. status = XchgSetSvcEnv(ServicesKey, pSvcInfo->snProvidorSvc[dwDependencyCnt],
  150. Environment, valueSize, ResourceEntry);
  151. if (status != ERROR_SUCCESS)
  152. goto error_exit;
  153. }
  154. }
  155. RegCloseKey(ServicesKey);
  156. #endif //ENVIRONMENT
  157. resourceStatus.ResourceState = ClusterResourceFailed;
  158. resourceStatus.WaitHint = 0;
  159. resourceStatus.CheckPoint = 1;
  160. for (dwSvcCnt=0;dwSvcCnt< ServiceInfoList.dwMaxSvcCnt; dwSvcCnt++)
  161. {
  162. pSvcInfo = &ServiceInfoList.SvcInfo[dwSvcCnt];
  163. //
  164. // Now open the requested service and the handle to its providor services
  165. //
  166. serviceHandle =
  167. XchgOpenSvc(pSvcInfo->snSvcName, ResourceEntry);
  168. if (serviceHandle == NULL)
  169. {
  170. status = GetLastError();
  171. goto error_exit;
  172. }
  173. ResourceEntry->ServiceHandle[dwSvcCnt][0] = serviceHandle;
  174. //get the handles for the child services
  175. for (dwDependencyCnt=0; dwDependencyCnt < pSvcInfo->dwDependencyCnt; dwDependencyCnt++)
  176. {
  177. serviceHandle =
  178. XchgOpenSvc(pSvcInfo->snSvcName, ResourceEntry);
  179. if (serviceHandle == NULL)
  180. {
  181. status = GetLastError();
  182. goto error_exit;
  183. }
  184. ResourceEntry->ServiceHandle[dwSvcCnt][dwDependencyCnt+1] = serviceHandle;
  185. }
  186. //start the top level services
  187. // the providor services will be started by scm
  188. if ( !StartServiceW( ResourceEntry->ServiceHandle[dwSvcCnt][0],
  189. 0,
  190. NULL ) )
  191. {
  192. status = GetLastError();
  193. if (status != ERROR_SERVICE_ALREADY_RUNNING) {
  194. /*
  195. ClusResLogEventByKeyData(ResourceEntry->ResourceKey,
  196. LOG_CRITICAL,
  197. RES_GENSVC_START_FAILED,
  198. sizeof(status),
  199. &status);
  200. */
  201. (g_LogEvent)(ResourceEntry->ResourceHandle,
  202. LOG_ERROR,
  203. L"Failed to start %1!ws! service. Error: %2!u!.\n",
  204. ServiceInfoList.SvcInfo[dwSvcCnt].snSvcName,
  205. status );
  206. status = ERROR_SERVICE_NEVER_STARTED;
  207. goto error_exit;
  208. }
  209. }
  210. }
  211. for (dwSvcCnt=0;dwSvcCnt< ServiceInfoList.dwMaxSvcCnt; dwSvcCnt++)
  212. {
  213. while (TRUE)
  214. {
  215. if ( !QueryServiceStatus( ResourceEntry->ServiceHandle[dwSvcCnt][0],
  216. &ServiceStatus ) ) {
  217. status = GetLastError();
  218. (g_LogEvent)(
  219. ResourceEntry->ResourceHandle,
  220. LOG_ERROR,
  221. L"XchgOnlineThread:Query Service Status failed %1!u!.\n",
  222. status );
  223. goto error_exit;
  224. }
  225. if ( ServiceStatus.dwCurrentState != SERVICE_START_PENDING ) {
  226. break;
  227. }
  228. Sleep(250);
  229. }
  230. if ( ServiceStatus.dwCurrentState != SERVICE_RUNNING ) {
  231. /*
  232. ClusResLogEventByKeyData(ResourceEntry->ResourceKey,
  233. LOG_CRITICAL,
  234. RES_GENSVC_FAILED_AFTER_START,
  235. sizeof(status),
  236. &status);
  237. */
  238. (g_LogEvent)(
  239. ResourceEntry->ResourceHandle,
  240. LOG_ERROR,
  241. L"Failed to start service %1!ws!, Error: %2!u!.\n",
  242. ServiceInfoList.SvcInfo[dwSvcCnt].snSvcName,
  243. ERROR_SERVICE_NEVER_STARTED );
  244. status = ERROR_SERVICE_NEVER_STARTED;
  245. goto error_exit;
  246. }
  247. }
  248. resourceStatus.ResourceState = ClusterResourceOnline;
  249. (g_LogEvent)(
  250. ResourceEntry->ResourceHandle,
  251. LOG_INFORMATION,
  252. L"Service is now on line.\n" );
  253. error_exit:
  254. #if ENVIRONMENT
  255. if ( Environment != NULL ) {
  256. RtlDestroyEnvironment( Environment );
  257. }
  258. #endif
  259. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  260. &resourceStatus );
  261. if ( resourceStatus.ResourceState == ClusterResourceOnline ) {
  262. ResourceEntry->Online = TRUE;
  263. } else {
  264. ResourceEntry->Online = FALSE;
  265. }
  266. return(status);
  267. } // CommonOnlineThread
  268. #endif
  269. RESID
  270. WINAPI
  271. XchgOpen(
  272. IN LPCWSTR ResourceName,
  273. IN HKEY ResourceKey,
  274. IN RESOURCE_HANDLE ResourceHandle
  275. )
  276. /*++
  277. Routine Description:
  278. Open routine for generic service resource.
  279. This routine gets a handle to the service controller, if we don't already have one,
  280. and then gets a handle to the specified service. The service handle is saved
  281. in the COMMON structure.
  282. Arguments:
  283. ResourceName - supplies the resource name
  284. ResourceKey - supplies a handle to the resource's cluster registry key
  285. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  286. is called.
  287. Return Value:
  288. RESID of created resource
  289. Zero on failure
  290. --*/
  291. {
  292. RESID svcResid = 0;
  293. DWORD status;
  294. HKEY parametersKey = NULL;
  295. HKEY resKey = NULL;
  296. PCOMMON_RESOURCE resourceEntry = NULL;
  297. LPWSTR resourceName = NULL;
  298. DWORD paramNameSize = 0;
  299. DWORD paramNameMaxSize = 0;
  300. HCLUSTER hCluster;
  301. DWORD returnSize;
  302. DWORD i;
  303. HANDLE hMutex;
  304. DWORD dwDependencyCnt, dwSvcCnt;
  305. PSERVICE_INFO pSvcInfo;
  306. //
  307. // Save the resource name.
  308. //
  309. resourceName = LocalAlloc( LMEM_FIXED,
  310. (wcslen(ResourceName) + 1) * sizeof(WCHAR) );
  311. if ( resourceName == NULL ) {
  312. (g_LogEvent)(
  313. ResourceHandle,
  314. LOG_ERROR,
  315. L"Unable to allocate name string.\n" );
  316. status = ERROR_NOT_ENOUGH_MEMORY;
  317. goto error_exit;
  318. }
  319. wcscpy( resourceName, ResourceName );
  320. //
  321. // Open registry parameters key for this resource.
  322. //
  323. status = ClusterRegOpenKey( ResourceKey,
  324. L"Parameters",
  325. KEY_READ,
  326. &parametersKey );
  327. if ( status != NO_ERROR ) {
  328. (g_LogEvent)(
  329. ResourceHandle,
  330. LOG_ERROR,
  331. L"Unable to open parameters key. Error: %1!u!.\n",
  332. status);
  333. goto error_exit;
  334. }
  335. //
  336. // Get a handle to our resource key so that we can get our name later
  337. // if we need to log an event.
  338. //
  339. status = ClusterRegOpenKey( ResourceKey,
  340. L"",
  341. KEY_READ,
  342. &resKey);
  343. if (status != ERROR_SUCCESS) {
  344. (g_LogEvent)(ResourceHandle,
  345. LOG_ERROR,
  346. L"Unable to open resource key. Error: %1!u!.\n",
  347. status );
  348. goto error_exit;
  349. }
  350. //
  351. // First get a handle to the service controller.
  352. //
  353. if ( g_ScHandle == NULL ) {
  354. g_ScHandle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
  355. if ( g_ScHandle == NULL ) {
  356. (g_LogEvent)(
  357. ResourceHandle,
  358. LOG_ERROR,
  359. L"Failed to open service control manager, error = %1!u!.\n",
  360. GetLastError());
  361. goto error_exit;
  362. }
  363. }
  364. resourceEntry = LocalAlloc( LMEM_FIXED, sizeof(COMMON_RESOURCE) );
  365. if ( resourceEntry == NULL ) {
  366. (g_LogEvent)(
  367. ResourceHandle,
  368. LOG_ERROR,
  369. L"Failed to allocate a service info structure.\n");
  370. goto error_exit;
  371. }
  372. ZeroMemory( resourceEntry, sizeof(COMMON_RESOURCE) );
  373. resourceEntry->ResourceHandle = ResourceHandle;
  374. resourceEntry->ResourceKey = resKey;
  375. resourceEntry->ParametersKey = parametersKey;
  376. resourceEntry->ResourceName = resourceName;
  377. //initialize the service handles to NULL
  378. for (dwSvcCnt=0; dwSvcCnt< ServiceInfoList.dwMaxSvcCnt; dwSvcCnt++)
  379. {
  380. pSvcInfo = &ServiceInfoList.SvcInfo[dwSvcCnt];
  381. for (dwDependencyCnt=0; dwDependencyCnt <= pSvcInfo->dwDependencyCnt; dwDependencyCnt++)
  382. {
  383. resourceEntry->ServiceHandle[dwSvcCnt][dwDependencyCnt] = NULL;
  384. }
  385. }
  386. hCluster = OpenCluster(NULL);
  387. if (hCluster == NULL) {
  388. (g_LogEvent)(
  389. ResourceHandle,
  390. LOG_ERROR,
  391. L"Failed to open cluster" );
  392. goto error_exit;
  393. }
  394. resourceEntry->hResource = OpenClusterResource(hCluster, ResourceName);
  395. CloseCluster(hCluster);
  396. if ( resourceEntry->hResource == NULL ) {
  397. (g_LogEvent)(
  398. ResourceHandle,
  399. LOG_ERROR,
  400. L"Failed to open resource" );
  401. goto error_exit;
  402. }
  403. //
  404. // Set any registry checkpoints that we need.
  405. //
  406. if ( RegSyncCount != 0 ) {
  407. returnSize = 0;
  408. status = ClusterResourceControl( resourceEntry->hResource,
  409. NULL,
  410. CLUSCTL_RESOURCE_GET_REGISTRY_CHECKPOINTS,
  411. NULL,
  412. 0,
  413. NULL,
  414. 0,
  415. &returnSize );
  416. if ( status != ERROR_SUCCESS ) {
  417. (g_LogEvent)(
  418. ResourceHandle,
  419. LOG_ERROR,
  420. L"Failed to get registry checkpoints, status %1!u!.\n",
  421. status );
  422. goto error_exit;
  423. }
  424. //
  425. // Set registry sync keys if we need them.
  426. //
  427. if ( returnSize == 0 ) {
  428. for ( i = 0; i < RegSyncCount; i++ ) {
  429. status = ClusterResourceControl( resourceEntry->hResource,
  430. NULL,
  431. CLUSCTL_RESOURCE_ADD_REGISTRY_CHECKPOINT,
  432. RegSync[i],
  433. (lstrlenW(RegSync[i]) + 1) * sizeof(WCHAR),
  434. NULL,
  435. 0,
  436. &returnSize );
  437. if ( status != ERROR_SUCCESS ) {
  438. (g_LogEvent)(
  439. ResourceHandle,
  440. LOG_ERROR,
  441. L"Failed to set registry checkpoint, status %1!u!.\n",
  442. status );
  443. goto error_exit;
  444. }
  445. }
  446. }
  447. }
  448. #ifdef COMMON_PARAMS_DEFINED
  449. //
  450. // Get any parameters... so we can handle the GET_DEPENDENCIES request.
  451. //
  452. CommonReadParameters( resourceEntry );
  453. // ignore status return
  454. #endif // COMMON_PARAMS_DEFINED
  455. #ifdef COMMON_MUTEX
  456. //
  457. // Check if more than one resource of this type.
  458. // N.B. Must have a lock for this case!
  459. //
  460. hMutex = CreateMutexW( NULL,
  461. FALSE,
  462. COMMON_MUTEX );
  463. if ( hMutex == NULL ) {
  464. status = GetLastError();
  465. (g_LogEvent)(
  466. ResourceHandle,
  467. LOG_ERROR,
  468. L"Failed to create global mutex, status %1!us!.\n",
  469. status );
  470. goto error_exit;
  471. }
  472. if ( WaitForSingleObject( hMutex, 0 ) == WAIT_TIMEOUT ) {
  473. //
  474. // A version of this service is already running
  475. //
  476. CloseHandle( hMutex );
  477. (g_LogEvent)(
  478. ResourceHandle,
  479. LOG_ERROR,
  480. L"Service is already running.\n" );
  481. status = ERROR_SERVICE_ALREADY_RUNNING;
  482. goto error_exit;
  483. }
  484. ASSERT( CommonMutex == NULL );
  485. CommonMutex = hMutex;
  486. #endif // COMMON_MUTEX
  487. svcResid = (RESID)resourceEntry;
  488. return(svcResid);
  489. error_exit:
  490. LocalFree( resourceName );
  491. LocalFree( resourceEntry );
  492. if ( parametersKey != NULL ) {
  493. ClusterRegCloseKey( parametersKey );
  494. }
  495. if ( resKey != NULL) {
  496. ClusterRegCloseKey( resKey );
  497. }
  498. return(FALSE);
  499. } // XchgOpen
  500. DWORD
  501. WINAPI
  502. XchgOnline(
  503. IN RESID ResourceId,
  504. IN OUT PHANDLE EventHandle
  505. )
  506. /*++
  507. Routine Description:
  508. Online routine for Common Service resource.
  509. Arguments:
  510. ResourceId - Supplies resource id to be brought online
  511. EventHandle - Supplies a pointer to a handle to signal on error.
  512. Return Value:
  513. ERROR_SUCCESS if successful.
  514. ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
  515. ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
  516. acquire 'ownership'.
  517. Win32 error code if other failure.
  518. --*/
  519. {
  520. DWORD status;
  521. PCOMMON_RESOURCE resourceEntry;
  522. resourceEntry = (PCOMMON_RESOURCE)ResourceId;
  523. if ( resourceEntry == NULL ) {
  524. DBG_PRINT( "Common: Online request for a nonexistent resource id 0x%p.\n",
  525. ResourceId );
  526. return(ERROR_RESOURCE_NOT_FOUND);
  527. }
  528. ClusWorkerTerminate( &resourceEntry->OnlineThread );
  529. status = ClusWorkerCreate( &resourceEntry->OnlineThread,
  530. COMMON_ONLINE_THREAD_ROUTINE,
  531. resourceEntry );
  532. if ( status == ERROR_SUCCESS ) {
  533. status = ERROR_IO_PENDING;
  534. }
  535. return(status);
  536. } // XchgOnline
  537. VOID
  538. WINAPI
  539. XchgTerminate(
  540. IN RESID ResourceId
  541. )
  542. /*++
  543. Routine Description:
  544. Terminate routine for Common Service resource.
  545. Arguments:
  546. ResourceId - Supplies resource id to be terminated
  547. Return Value:
  548. None.
  549. --*/
  550. {
  551. SERVICE_STATUS ServiceStatus;
  552. PCOMMON_RESOURCE resourceEntry;
  553. DWORD dwSvcCnt;
  554. PSERVICE_INFO pSvcInfo;
  555. DWORD dwDependencyCnt;
  556. resourceEntry = (PCOMMON_RESOURCE)ResourceId;
  557. if ( resourceEntry == NULL ) {
  558. DBG_PRINT( "Common: Offline request for a nonexistent resource id 0x%p.\n",
  559. ResourceId );
  560. return;
  561. }
  562. (g_LogEvent)(
  563. resourceEntry->ResourceHandle,
  564. LOG_INFORMATION,
  565. L"Offline request.\n" );
  566. ClusWorkerTerminate( &resourceEntry->OnlineThread );
  567. for (dwSvcCnt=0;dwSvcCnt< ServiceInfoList.dwMaxSvcCnt; dwSvcCnt++)
  568. {
  569. pSvcInfo = &ServiceInfoList.SvcInfo[dwSvcCnt];
  570. //stop the service, lowest order service first
  571. for (dwDependencyCnt= 0; dwDependencyCnt<= pSvcInfo->dwDependencyCnt; dwDependencyCnt++)
  572. {
  573. if ( resourceEntry->ServiceHandle[dwSvcCnt][pSvcInfo->dwDependencyCnt-dwDependencyCnt]
  574. != NULL )
  575. {
  576. DWORD retryTime = 30*1000; // wait 30 secs for shutdown
  577. DWORD retryTick = 300; // 300 msec at a time
  578. DWORD status;
  579. BOOL didStop = FALSE;
  580. //stop the child service
  581. for (;;)
  582. {
  583. status = (ControlService(
  584. resourceEntry->ServiceHandle[dwSvcCnt][pSvcInfo->dwDependencyCnt - dwDependencyCnt],
  585. (didStop
  586. ? SERVICE_CONTROL_INTERROGATE
  587. : SERVICE_CONTROL_STOP),
  588. &ServiceStatus )
  589. ? NO_ERROR
  590. : GetLastError());
  591. if (status == NO_ERROR) {
  592. didStop = TRUE;
  593. if (ServiceStatus.dwCurrentState == SERVICE_STOPPED) {
  594. (g_LogEvent)(
  595. resourceEntry->ResourceHandle,
  596. LOG_INFORMATION,
  597. L"Service stopped.\n" );
  598. break;
  599. }
  600. }
  601. if (status == ERROR_EXCEPTION_IN_SERVICE ||
  602. status == ERROR_PROCESS_ABORTED ||
  603. status == ERROR_SERVICE_NOT_ACTIVE) {
  604. (g_LogEvent)(
  605. resourceEntry->ResourceHandle,
  606. LOG_INFORMATION,
  607. L"Service died; status = %1!u!.\n",
  608. status);
  609. break;
  610. }
  611. if ((retryTime -= retryTick) <= 0) {
  612. (g_LogEvent)(
  613. resourceEntry->ResourceHandle,
  614. LOG_ERROR,
  615. L"Service did not stop; giving up.\n" );
  616. break;
  617. }
  618. (g_LogEvent)(
  619. resourceEntry->ResourceHandle,
  620. LOG_INFORMATION,
  621. L"Offline: retrying...\n" );
  622. Sleep(retryTick);
  623. }
  624. CloseServiceHandle( resourceEntry->ServiceHandle[dwSvcCnt][pSvcInfo->dwDependencyCnt - dwDependencyCnt] );
  625. resourceEntry->ServiceHandle[dwSvcCnt][pSvcInfo->dwDependencyCnt - dwDependencyCnt] = NULL;
  626. }
  627. }
  628. }
  629. resourceEntry->Online = FALSE;
  630. } // XchgTerminate
  631. static
  632. DWORD
  633. WINAPI
  634. XchgOffline(
  635. IN RESID ResourceId
  636. )
  637. /*++
  638. Routine Description:
  639. Offline routine for Common Service resource.
  640. Arguments:
  641. ResourceId - Supplies the resource to be taken offline
  642. Return Value:
  643. ERROR_SUCCESS - always successful.
  644. --*/
  645. {
  646. XchgTerminate( ResourceId );
  647. return(ERROR_SUCCESS);
  648. } // XchgOffline
  649. BOOL
  650. WINAPI
  651. XchgIsAlive(
  652. IN RESID ResourceId
  653. )
  654. /*++
  655. Routine Description:
  656. IsAlive routine for Common service resource.
  657. Arguments:
  658. ResourceId - Supplies the resource id to be polled.
  659. Return Value:
  660. TRUE - if service is running
  661. FALSE - if service is in any other state
  662. --*/
  663. {
  664. return( XchgVerifyService( ResourceId, TRUE ) );
  665. } // CommonIsAlive
  666. BOOL
  667. XchgVerifyService(
  668. IN RESID ResourceId,
  669. IN BOOL IsAliveFlag)
  670. /*++
  671. Routine Description:
  672. Verify that a specified service is running
  673. Arguments:
  674. ResourceId - Supplies the resource id
  675. IsAliveFlag - Says this is an IsAlive call - used only for debug print
  676. Return Value:
  677. TRUE - if service is running or starting
  678. FALSE - service is in any other state
  679. --*/
  680. {
  681. SERVICE_STATUS ServiceStatus;
  682. PCOMMON_RESOURCE resourceEntry;
  683. DWORD status = ERROR_SUCCESS;
  684. BOOL bRet = TRUE;
  685. DWORD dwSvcCnt;
  686. resourceEntry = (PCOMMON_RESOURCE)ResourceId;
  687. if ( resourceEntry == NULL ) {
  688. DBG_PRINT( "Common: IsAlive request for a nonexistent resource id 0x%p.\n",
  689. ResourceId );
  690. bRet = FALSE;
  691. goto error_exit;
  692. }
  693. for (dwSvcCnt=0; dwSvcCnt< ServiceInfoList.dwMaxSvcCnt; dwSvcCnt++)
  694. {
  695. if ( !QueryServiceStatus( resourceEntry->ServiceHandle[dwSvcCnt][0],
  696. &ServiceStatus ) )
  697. {
  698. status = GetLastError();
  699. (g_LogEvent)(
  700. resourceEntry->ResourceHandle,
  701. LOG_ERROR,
  702. L"XchgOnlineThread:Query Service Status failed %1!u!.\n",
  703. status );
  704. bRet = FALSE;
  705. goto error_exit;
  706. }
  707. if ((ServiceStatus.dwCurrentState != SERVICE_RUNNING)&&(ServiceStatus.dwCurrentState != SERVICE_START_PENDING))
  708. {
  709. (g_LogEvent)(
  710. resourceEntry->ResourceHandle,
  711. LOG_ERROR,
  712. L"Failed the IsAlive test. Current State is %1!u!.\n",
  713. ServiceStatus.dwCurrentState );
  714. bRet = FALSE;
  715. goto error_exit;
  716. }
  717. }
  718. error_exit:
  719. return(bRet);
  720. } // Verify Service
  721. BOOL
  722. WINAPI
  723. XchgLooksAlive(
  724. IN RESID ResourceId
  725. )
  726. /*++
  727. Routine Description:
  728. LooksAlive routine for Common Service resource.
  729. Arguments:
  730. ResourceId - Supplies the resource id to be polled.
  731. Return Value:
  732. TRUE - Resource looks like it is alive and well
  733. FALSE - Resource looks like it is toast.
  734. --*/
  735. {
  736. return( XchgVerifyService( ResourceId, FALSE ) );
  737. } // CommonLooksAlive
  738. VOID
  739. WINAPI
  740. XchgClose(
  741. IN RESID ResourceId
  742. )
  743. /*++
  744. Routine Description:
  745. Close routine for Common Services resource.
  746. This routine will stop the service, and delete the cluster
  747. information regarding that service.
  748. Arguments:
  749. ResourceId - Supplies resource id to be closed
  750. Return Value:
  751. None.
  752. --*/
  753. {
  754. PCOMMON_RESOURCE resourceEntry;
  755. DWORD errorCode;
  756. HANDLE hMutex;
  757. resourceEntry = (PCOMMON_RESOURCE)ResourceId;
  758. if ( resourceEntry == NULL ) {
  759. DBG_PRINT( "Common: Close request for a nonexistent resource id 0x%p\n",
  760. ResourceId );
  761. return;
  762. }
  763. (g_LogEvent)(
  764. resourceEntry->ResourceHandle,
  765. LOG_INFORMATION,
  766. L"Close request.\n" );
  767. //
  768. // Shut it down if it's on line
  769. //
  770. XchgTerminate( ResourceId );
  771. ClusterRegCloseKey( resourceEntry->ParametersKey );
  772. ClusterRegCloseKey( resourceEntry->ResourceKey );
  773. CloseClusterResource( resourceEntry->hResource );
  774. #ifdef COMMON_MUTEX
  775. hMutex = CommonMutex;
  776. CommonMutex = NULL;
  777. ReleaseMutex( hMutex );
  778. CloseHandle( hMutex );
  779. #endif
  780. LocalFree( resourceEntry->ResourceName );
  781. LocalFree( resourceEntry );
  782. } // XchgClose
  783. HANDLE
  784. XchgOpenSvc(
  785. IN SERVICE_NAME ServiceName,
  786. IN PCOMMON_RESOURCE ResourceEntry
  787. )
  788. /*++
  789. Routine Description:
  790. opens the service and sets it to manual mode.
  791. Arguments:
  792. ResourceId - Supplies resource id to be closed
  793. Return Value:
  794. None.
  795. --*/
  796. {
  797. HANDLE serviceHandle=NULL;
  798. DWORD status=ERROR_SUCCESS;
  799. serviceHandle = OpenService( g_ScHandle, ServiceName, SERVICE_ALL_ACCESS );
  800. if ( serviceHandle == NULL ) {
  801. status = GetLastError();
  802. /*
  803. ClusResLogEventByKeyData(ResourceEntry->ResourceKey,
  804. LOG_CRITICAL,
  805. RES_GENSVC_OPEN_FAILED,
  806. sizeof(status),
  807. &status);
  808. */
  809. (g_LogEvent)(
  810. ResourceEntry->ResourceHandle,
  811. LOG_ERROR,
  812. L"Failed to open service, error = %1!u!.\n",
  813. status );
  814. goto error_exit;
  815. }
  816. //
  817. // Make sure service is set to manual start.
  818. //
  819. ChangeServiceConfig( serviceHandle,
  820. SERVICE_NO_CHANGE,
  821. SERVICE_DEMAND_START, // Manual start
  822. SERVICE_NO_CHANGE,
  823. NULL,
  824. NULL,
  825. NULL,
  826. NULL,
  827. NULL,
  828. NULL,
  829. NULL );
  830. error_exit:
  831. if (status != ERROR_SUCCESS)
  832. SetLastError(status);
  833. return(serviceHandle);
  834. }// XchgOpenSvc
  835. DWORD
  836. XchgSetSvcEnv(
  837. IN HKEY ServicesKey,
  838. IN SERVICE_NAME ServiceName,
  839. IN LPVOID Environment,
  840. IN DWORD ValueSize,
  841. IN PCOMMON_RESOURCE ResourceEntry
  842. )
  843. /*++
  844. Routine Description:
  845. opens the service and sets it to manual mode.
  846. Arguments:
  847. ResourceId - Supplies resource id to be closed
  848. Return Value:
  849. None.
  850. --*/
  851. {
  852. DWORD status = ERROR_SUCCESS;
  853. HKEY hKey;
  854. status = RegOpenKeyExW( ServicesKey,
  855. ServiceName,
  856. 0,
  857. KEY_READ | KEY_WRITE,
  858. &hKey );
  859. if (status != ERROR_SUCCESS)
  860. {
  861. (g_LogEvent)(
  862. ResourceEntry->ResourceHandle,
  863. LOG_ERROR,
  864. L"XchgSet: Failed to open service key for %1!ws!, error = %2!u!.\n",
  865. ServiceName, status );
  866. goto error_exit;
  867. }
  868. status = RegSetValueExW( hKey,
  869. L"Environment",
  870. 0,
  871. REG_MULTI_SZ,
  872. Environment,
  873. ValueSize );
  874. RegCloseKey(hKey);
  875. if (status != ERROR_SUCCESS)
  876. {
  877. (g_LogEvent)(
  878. ResourceEntry->ResourceHandle,
  879. LOG_ERROR,
  880. L"XchgSet:Failed to set service environment value, error = %1!u!.\n",
  881. status );
  882. goto error_exit;
  883. }
  884. error_exit:
  885. return(status);
  886. }
  887. // CommonSetSvcEnv
  888. /*
  889. VOID
  890. ClusResLogEventWithName0(
  891. IN HKEY hResourceKey,
  892. IN DWORD LogLevel,
  893. IN DWORD LogModule,
  894. IN LPSTR FileName,
  895. IN DWORD LineNumber,
  896. IN DWORD MessageId,
  897. IN DWORD dwByteCount,
  898. IN PVOID lpBytes
  899. )
  900. */
  901. /*++
  902. Routine Description:
  903. Logs an event to the eventlog. The display name of the resource is retrieved
  904. and passed as the first insertion string.
  905. Arguments:
  906. hResourceKey - Supplies the cluster resource key.
  907. LogLevel - Supplies the logging level, one of
  908. LOG_CRITICAL 1
  909. LOG_UNUSUAL 2
  910. LOG_NOISE 3
  911. LogModule - Supplies the module ID.
  912. FileName - Supplies the filename of the caller
  913. LineNumber - Supplies the line number of the caller
  914. MessageId - Supplies the message ID to be logged.
  915. dwByteCount - Supplies the number of error-specific bytes to log. If this
  916. is zero, lpBytes is ignored.
  917. lpBytes - Supplies the error-specific bytes to log.
  918. Return Value:
  919. ERROR_SUCCESS if successful
  920. Win32 error code otherwise
  921. --*/
  922. /*
  923. {
  924. DWORD BufSize;
  925. DWORD Status;
  926. WCHAR ResourceName[80];
  927. DWORD dwType;
  928. //
  929. // Get the display name for this resource.
  930. //
  931. BufSize = sizeof(ResourceName);
  932. Status = ClusterRegQueryValue( hResourceKey,
  933. CLUSREG_NAME_RES_NAME,
  934. &dwType,
  935. (LPBYTE)ResourceName,
  936. &BufSize );
  937. if (Status != ERROR_SUCCESS) {
  938. ResourceName[0] = '\0';
  939. } else {
  940. ResourceName[79] = '\0';
  941. }
  942. ClusterLogEvent1(LogLevel,
  943. LogModule,
  944. FileName,
  945. LineNumber,
  946. MessageId,
  947. dwByteCount,
  948. lpBytes,
  949. ResourceName);
  950. return;
  951. }
  952. */
  953. CLRES_V1_FUNCTION_TABLE( ExchangeFunctionTable, // Name
  954. CLRES_VERSION_V1_00, // Version
  955. Xchg, // Prefix
  956. NULL, // Arbitrate
  957. NULL, // Release
  958. NULL, // ResControl
  959. NULL ); // ResTypeControl