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.

1197 lines
37 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. restore.c
  5. Abstract:
  6. Functions supporting the restoration of the cluster database
  7. to the quorum disk
  8. Author:
  9. Chittur Subbaraman (chitturs) 27-Oct-1998
  10. Revision History:
  11. --*/
  12. #include "initp.h"
  13. #include "winioctl.h"
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. //
  17. // Static global variables used only in this file
  18. //
  19. // static LPWSTR szRdbpNodeNameList = NULL;
  20. // static DWORD dwRdbpNodeCount = 0;
  21. /****
  22. @func DWORD | RdbStopSvcOnNodes | Stop the requested service
  23. on the given node list
  24. @parm IN PNM_NODE_ENUM2 | pNodeEnum | Pointer to the list of
  25. nodes in which the requested service has to be stopped.
  26. @rdesc Returns a Win32 error code on failure. ERROR_SUCCESS on success.
  27. @comm This function attempts to stop the chosen service on the chosen
  28. list of nodes. If it fails in stopping the service on any
  29. one of the nodes, it returns a Win32 error code.
  30. At this time, this function DOES NOT STOP a cluster service
  31. which is run as a process in a remote node.
  32. @xref <f RdbStartSvcOnNodes>
  33. ****/
  34. DWORD
  35. RdbStopSvcOnNodes(
  36. IN PNM_NODE_ENUM2 pNodeEnum,
  37. IN LPCWSTR lpszServiceName
  38. )
  39. {
  40. SC_HANDLE hService;
  41. SC_HANDLE hSCManager;
  42. DWORD dwStatus = ERROR_SUCCESS;
  43. DWORD dwRetryTime;
  44. DWORD dwRetryTick;
  45. SERVICE_STATUS serviceStatus;
  46. WCHAR szNodeName[CS_MAX_NODE_NAME_LENGTH + 1];
  47. DWORD i;
  48. BOOL bStopCommandGiven;
  49. //
  50. // Chittur Subbaraman (chitturs) - 10/30/98
  51. //
  52. #if 0
  53. //
  54. // Allocate storage for the node names which you would use to
  55. // start the service later. Memory is freed in RdbpStartSvcOnNodes
  56. //
  57. if ( pNodeEnum->NodeCount > 0 )
  58. {
  59. szRdbpNodeNameList = ( LPWSTR ) LocalAlloc( LMEM_FIXED,
  60. sizeof ( WCHAR) *
  61. ( CS_MAX_NODE_NAME_LENGTH + 1 ) *
  62. pNodeEnum->NodeCount );
  63. if ( szRdbpNodeNameList == NULL )
  64. {
  65. ClRtlLogPrint(LOG_UNUSUAL,
  66. "[INIT] RdbStopSvcOnNodes: Unable to allocate memory for node names, Error = %1!d!\n",
  67. GetLastError());
  68. }
  69. }
  70. #endif
  71. //
  72. // Walk through the list of nodes
  73. //
  74. for ( i=0; i<pNodeEnum->NodeCount; i++ )
  75. {
  76. lstrcpyW( szNodeName, pNodeEnum->NodeList[i].NodeName );
  77. //
  78. // Skip the local node, if it is included in the list
  79. //
  80. if ( ( lstrcmpW ( szNodeName, NmLocalNodeName ) == 0 ) )
  81. {
  82. continue;
  83. }
  84. //
  85. // Try for 2 minutes max to stop the service on a node. Retry
  86. // in steps of 5 secs.
  87. //
  88. dwRetryTime = 120 * 1000;
  89. dwRetryTick = 05 * 1000;
  90. //
  91. // Open a handle to the service control manager
  92. //
  93. hSCManager = OpenSCManager( szNodeName,
  94. NULL,
  95. SC_MANAGER_ALL_ACCESS );
  96. if ( hSCManager == NULL )
  97. {
  98. dwStatus = GetLastError();
  99. ClRtlLogPrint(LOG_UNUSUAL,
  100. "[INIT] RdbStopSvcOnNodes: Unable to open SC manager on node %1!ws!, Error = %2!d!\n",
  101. szNodeName,
  102. dwStatus);
  103. continue;
  104. }
  105. //
  106. // Open a handle to the service
  107. //
  108. hService = OpenService( hSCManager,
  109. lpszServiceName,
  110. SERVICE_ALL_ACCESS );
  111. CloseServiceHandle( hSCManager );
  112. if ( hService == NULL )
  113. {
  114. dwStatus = GetLastError();
  115. ClRtlLogPrint(LOG_UNUSUAL,
  116. "[INIT] RdbStopSvcOnNodes: Unable to open handle to %1!ws! service on node %2!ws!, Error = %3!d!\n",
  117. lpszServiceName,
  118. szNodeName,
  119. dwStatus);
  120. continue;
  121. }
  122. //
  123. // Check whether the service is already in the SERVICE_STOPPED
  124. // state.
  125. //
  126. if ( QueryServiceStatus( hService,
  127. &serviceStatus ) )
  128. {
  129. if ( serviceStatus.dwCurrentState == SERVICE_STOPPED )
  130. {
  131. ClRtlLogPrint(LOG_NOISE,
  132. "[INIT] RdbStopSvcOnNodes: %1!ws! on node %2!ws! already stopped\n",
  133. lpszServiceName,
  134. szNodeName);
  135. CloseServiceHandle( hService );
  136. continue;
  137. }
  138. }
  139. bStopCommandGiven = FALSE;
  140. while ( TRUE )
  141. {
  142. dwStatus = ERROR_SUCCESS;
  143. if ( bStopCommandGiven == TRUE )
  144. {
  145. if ( QueryServiceStatus( hService,
  146. &serviceStatus ) )
  147. {
  148. if ( serviceStatus.dwCurrentState == SERVICE_STOPPED )
  149. {
  150. //
  151. // Succeeded in stopping the service
  152. //
  153. ClRtlLogPrint(LOG_NOISE,
  154. "[INIT] RdbStopSvcOnNodes: %1!ws! on node %2!ws! stopped successfully\n",
  155. lpszServiceName,
  156. szNodeName);
  157. break;
  158. }
  159. } else
  160. {
  161. dwStatus = GetLastError();
  162. ClRtlLogPrint(LOG_ERROR,
  163. "[INIT] RdbStopSvcOnNodes: Error %3!d! in querying status of %1!ws! on node %2!ws!\n",
  164. lpszServiceName,
  165. szNodeName,
  166. dwStatus);
  167. }
  168. } else
  169. {
  170. if ( ControlService( hService,
  171. SERVICE_CONTROL_STOP,
  172. &serviceStatus ) )
  173. {
  174. bStopCommandGiven = TRUE;
  175. dwStatus = ERROR_SUCCESS;
  176. } else
  177. {
  178. dwStatus = GetLastError();
  179. ClRtlLogPrint(LOG_ERROR,
  180. "[INIT] RdbStopSvcOnNodes: Error %3!d! in trying to stop %1!ws! on node %2!ws!\n",
  181. lpszServiceName,
  182. szNodeName,
  183. dwStatus);
  184. }
  185. }
  186. if ( ( dwStatus == ERROR_EXCEPTION_IN_SERVICE ) ||
  187. ( dwStatus == ERROR_PROCESS_ABORTED ) ||
  188. ( dwStatus == ERROR_SERVICE_NOT_ACTIVE ) )
  189. {
  190. //
  191. // The service is essentially in a terminated state
  192. //
  193. ClRtlLogPrint(LOG_UNUSUAL,
  194. "[INIT] RdbStopSvcOnNodes: %1!ws! on node %2!ws! died/inactive\n",
  195. lpszServiceName,
  196. szNodeName);
  197. dwStatus = ERROR_SUCCESS;
  198. break;
  199. }
  200. if ( ( dwRetryTime -= dwRetryTick ) <= 0 )
  201. {
  202. //
  203. // All tries to stop the service failed, exit from this
  204. // function with an error code
  205. //
  206. ClRtlLogPrint(LOG_UNUSUAL,
  207. "[INIT] RdbStopSvcOnNodes: Service %1!ws! service on node %2!ws! did not stop, giving up...\n",
  208. lpszServiceName,
  209. szNodeName);
  210. dwStatus = ERROR_TIMEOUT;
  211. break;
  212. }
  213. ClRtlLogPrint(LOG_NOISE,
  214. "[INIT] RdbStopSvcOnNodes: Trying to stop %1!ws! on node %2!ws!\n",
  215. lpszServiceName,
  216. szNodeName);
  217. //
  218. // Sleep for a while and retry stopping the service
  219. //
  220. Sleep( dwRetryTick );
  221. } // while
  222. CloseServiceHandle( hService );
  223. if ( dwStatus != ERROR_SUCCESS )
  224. {
  225. goto FnExit;
  226. }
  227. #if 0
  228. //
  229. // Save the node name for later use when starting the service
  230. //
  231. if ( szRdbpNodeNameList != NULL )
  232. {
  233. lstrcpyW( szRdbpNodeNameList + dwRdbpNodeCount *
  234. ( CS_MAX_NODE_NAME_LENGTH + 1 ),
  235. szNodeName );
  236. dwRdbpNodeCount++;
  237. }
  238. #endif
  239. } // for
  240. FnExit:
  241. return( dwStatus );
  242. }
  243. /****
  244. @func DWORD | RdbGetRestoreDbParams | Check the registry and see
  245. whether the restore database option is set. If so, get the
  246. params.
  247. @parm IN HKEY | hKey | Handle to the cluster service parameters key
  248. @comm This function attempts read the registry and return the
  249. parameters for the restore database operation.
  250. @xref <f CspGetServiceParams>
  251. ****/
  252. VOID
  253. RdbGetRestoreDbParams(
  254. IN HKEY hClusSvcKey
  255. )
  256. {
  257. DWORD dwLength = 0;
  258. DWORD dwType;
  259. DWORD dwStatus;
  260. DWORD dwForceDatabaseRestore;
  261. //
  262. // Chittur Subbaraman (chitturs) - 10/30/98
  263. //
  264. if ( hClusSvcKey == NULL )
  265. {
  266. return;
  267. }
  268. //
  269. // Try to query the clussvc parameters key. If the RestoreDatabase
  270. // value is present, then get the length of the restore database
  271. // path.
  272. //
  273. if ( ClRtlRegQueryString( hClusSvcKey,
  274. CLUSREG_NAME_SVC_PARAM_RESTORE_DB,
  275. REG_SZ,
  276. &CsDatabaseRestorePath,
  277. &dwLength,
  278. &dwLength ) != ERROR_SUCCESS )
  279. {
  280. goto FnExit;
  281. }
  282. ClRtlLogPrint(LOG_NOISE,
  283. "[INIT] RdbGetRestoreDbparams: Restore Cluster Database is in progress...\n");
  284. CsDatabaseRestore = TRUE;
  285. //
  286. // Try to query the clussvc parameters key for the ForceRestoreDatabase
  287. // value. Don't bother to delete the param, since the
  288. // RestoreClusterDatabase API will do it.
  289. //
  290. if ( ClRtlRegQueryDword( hClusSvcKey,
  291. CLUSREG_NAME_SVC_PARAM_FORCE_RESTORE_DB,
  292. &dwForceDatabaseRestore,
  293. NULL ) != ERROR_SUCCESS )
  294. {
  295. ClRtlLogPrint(LOG_NOISE,
  296. "[INIT] RdbGetRestoreDbparams: ForceRestoreDatabase params key is absent or unreadable\n"
  297. );
  298. goto FnExit;
  299. }
  300. CsForceDatabaseRestore = TRUE;
  301. //
  302. // Try to query the clussvc parameters key for the NewQuorumDriveLetter
  303. // value. Check for the validity of the drive letter later when
  304. // you attempt to fix up stuff.
  305. //
  306. dwLength = 0;
  307. if ( ClRtlRegQueryString( hClusSvcKey,
  308. CLUSREG_NAME_SVC_PARAM_QUORUM_DRIVE_LETTER,
  309. REG_SZ,
  310. &CsQuorumDriveLetter,
  311. &dwLength,
  312. &dwLength ) != ERROR_SUCCESS )
  313. {
  314. ClRtlLogPrint(LOG_NOISE,
  315. "[INIT] RdbGetRestoreDbparams: NewQuorumDriveLetter params key is absent or unreadable\n"
  316. );
  317. }
  318. FnExit:
  319. //
  320. // Make sure you delete these registry values read above. It is OK if you fail in finding
  321. // some of these values. Note that the RestoreClusterDatabase API will also try to clean
  322. // up these values. We cannot assume that the API will clean up these values since the
  323. // values could be set by (a) ASR (b) A user by hand, and not always by the API.
  324. //
  325. RdbpDeleteRestoreDbParams();
  326. }
  327. /****
  328. @func DWORD | RdbFixupQuorumDiskSignature | Fixup the quorum disk
  329. signature with the supplied value, if necessary
  330. @parm IN DWORD | dwSignature | The new signature which must be
  331. written to the quorum disk.
  332. @rdesc Returns a non-zero value if successful. 0 on failure.
  333. @comm This function attempts to write the given signature into
  334. the physical quorum disk, if necessary.
  335. @xref <f RdbStartSvcOnNodes>
  336. ****/
  337. BOOL
  338. RdbFixupQuorumDiskSignature(
  339. IN DWORD dwSignature
  340. )
  341. {
  342. HANDLE hFile = INVALID_HANDLE_VALUE;
  343. DWORD dwStatus;
  344. BOOL bStatus = 1;
  345. //
  346. // Chittur Subbaraman (chitturs) - 10/30/98
  347. //
  348. if ( ( dwSignature == 0 ) ||
  349. ( lstrlenW ( CsQuorumDriveLetter ) != 2 ) ||
  350. ( !iswalpha( CsQuorumDriveLetter[0] ) ) ||
  351. ( CsQuorumDriveLetter[1] != L':' ) )
  352. {
  353. bStatus = 0;
  354. goto FnExit;
  355. }
  356. //
  357. // Now try to open the quorum disk device
  358. //
  359. if ( ( dwStatus = RdbpOpenDiskDevice ( CsQuorumDriveLetter, &hFile ) )
  360. != ERROR_SUCCESS )
  361. {
  362. ClRtlLogPrint(LOG_ERROR,
  363. "[INIT] RdbFixupQuorumDiskSignature: Error %1!d! in opening %2!ws!\n",
  364. dwStatus,
  365. CsQuorumDriveLetter
  366. );
  367. bStatus = 0;
  368. goto FnExit;
  369. }
  370. //
  371. // Get the signature from the drive, compare it with the input
  372. // parameter and if they are different, write new signature to
  373. // disk.
  374. //
  375. if ( ( dwStatus = RdbpCompareAndWriteSignatureToDisk( hFile, dwSignature ) )
  376. != ERROR_SUCCESS )
  377. {
  378. ClRtlLogPrint(LOG_ERROR,
  379. "[INIT] RdbFixupQuorumDiskSignature: Error %1!d! in attempting to write signature to %2!ws!\n",
  380. dwStatus,
  381. CsQuorumDriveLetter
  382. );
  383. bStatus = 0;
  384. goto FnExit;
  385. }
  386. FnExit:
  387. if ( hFile != INVALID_HANDLE_VALUE )
  388. {
  389. CloseHandle( hFile );
  390. }
  391. return ( bStatus );
  392. }
  393. /****
  394. @func DWORD | RdbpOpenDiskDevice | Open and get a handle
  395. to a physical disk device
  396. @parm IN LPCWSTR | lpDriveLetter | The disk drive letter.
  397. @parm OUT PHANDLE | pFileHandle | Pointer to the handle to the open
  398. device.
  399. @rdesc Returns ERROR_SUCCESS if successful. A Win32 error code on
  400. failure.
  401. @comm This function attempts to open a disk device and return a
  402. handle to it. Different ways are used to open the device.
  403. @xref <f RdbFixupQuorumDiskSignature>
  404. ****/
  405. DWORD
  406. RdbpOpenDiskDevice(
  407. IN LPCWSTR lpDriveLetter,
  408. OUT PHANDLE pFileHandle
  409. )
  410. {
  411. HANDLE hFile = INVALID_HANDLE_VALUE;
  412. DWORD accessMode;
  413. DWORD shareMode;
  414. DWORD dwStatus;
  415. BOOL bFailed = FALSE;
  416. WCHAR deviceNameString[128];
  417. //
  418. // Chittur Subbaraman (chitturs) - 10/30/98
  419. //
  420. // Note it is important to access the device with 0 access mode
  421. // so that the file open code won't do extra I/O to the device.
  422. //
  423. shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
  424. accessMode = GENERIC_READ | GENERIC_WRITE;
  425. lstrcpyW( deviceNameString, L"\\\\.\\" );
  426. lstrcatW( deviceNameString, lpDriveLetter );
  427. hFile = CreateFileW( deviceNameString,
  428. accessMode,
  429. shareMode,
  430. NULL,
  431. OPEN_EXISTING,
  432. 0,
  433. NULL );
  434. if ( hFile == INVALID_HANDLE_VALUE )
  435. {
  436. dwStatus = GetLastError();
  437. goto FnExit;
  438. }
  439. dwStatus = ERROR_SUCCESS;
  440. *pFileHandle = hFile;
  441. FnExit:
  442. return( dwStatus );
  443. }
  444. /****
  445. @func DWORD | RdbpCompareAndWriteSignatureToDisk | Compare the
  446. signature on disk with the input parameter and if they
  447. are not the same, write the input parameter as a new signature.
  448. @parm IN HANDLE | hFile | Handle to the disk device.
  449. @parm IN DWORD | dwSignature | Signature to be compared with
  450. exisiting disk signature.
  451. @rdesc Returns ERROR_SUCCESS if successful. A Win32 error code on
  452. failure.
  453. @comm This function attempts to first get the drive layout, read the
  454. signature information, and then if necessary write back a
  455. new signature to the drive. [This code is stolen from Rod's
  456. clusdisk\test\disktest.c and then adapted to suit our needs.]
  457. @xref <f RdbFixupQuorumDiskSignature>
  458. ****/
  459. DWORD
  460. RdbpCompareAndWriteSignatureToDisk(
  461. IN HANDLE hFile,
  462. IN DWORD dwSignature
  463. )
  464. {
  465. DWORD dwStatus;
  466. DWORD dwBytesReturned;
  467. DWORD dwDriveLayoutSize;
  468. PDRIVE_LAYOUT_INFORMATION pDriveLayout = NULL;
  469. //
  470. // Chittur Subbaraman (chitturs) - 10/30/98
  471. //
  472. if ( !ClRtlGetDriveLayoutTable( hFile, &pDriveLayout, &dwBytesReturned )) {
  473. dwStatus = GetLastError();
  474. ClRtlLogPrint(LOG_ERROR,
  475. "[INIT] RdbpCompareAndWriteSignatureToDisk: Error %1!d! in getting "
  476. "drive layout from %2!ws!\n",
  477. dwStatus,
  478. CsQuorumDriveLetter
  479. );
  480. goto FnExit;
  481. }
  482. dwDriveLayoutSize = sizeof( DRIVE_LAYOUT_INFORMATION ) +
  483. ( sizeof( PARTITION_INFORMATION ) *
  484. ( pDriveLayout->PartitionCount - 1 ) );
  485. if ( dwBytesReturned < dwDriveLayoutSize )
  486. {
  487. ClRtlLogPrint(LOG_ERROR,
  488. "[INIT] RdbpCompareAndWriteSignatureToDisk: Error reading driveLayout information. Expected %1!u! bytes, got %2!u! bytes.\n",
  489. dwDriveLayoutSize,
  490. dwBytesReturned
  491. );
  492. dwStatus = ERROR_INSUFFICIENT_BUFFER;
  493. goto FnExit;
  494. }
  495. if ( pDriveLayout->Signature == dwSignature )
  496. {
  497. dwStatus = ERROR_SUCCESS;
  498. ClRtlLogPrint(LOG_NOISE,
  499. "[INIT] RdbpCompareAndWriteSignatureToDisk: Disk %1!ws! signature is same as in registry. No fixup needed\n",
  500. CsQuorumDriveLetter
  501. );
  502. goto FnExit;
  503. }
  504. //
  505. // Change just the signature field and send an ioctl down
  506. //
  507. pDriveLayout->Signature = dwSignature;
  508. if ( !DeviceIoControl( hFile,
  509. IOCTL_DISK_SET_DRIVE_LAYOUT,
  510. pDriveLayout,
  511. dwDriveLayoutSize,
  512. NULL,
  513. 0,
  514. &dwBytesReturned,
  515. FALSE ) )
  516. {
  517. dwStatus = GetLastError();
  518. ClRtlLogPrint(LOG_ERROR,
  519. "[INIT] RdbpCompareAndWriteSignatureToDisk: Error %1!d! in setting drive layout to %2!ws!\n",
  520. dwStatus,
  521. CsQuorumDriveLetter
  522. );
  523. goto FnExit;
  524. }
  525. dwStatus = ERROR_SUCCESS;
  526. ClRtlLogPrint(LOG_NOISE,
  527. "[INIT] RdbpCompareAndWriteSignatureToDisk: Quorum disk signature fixed successfully\n"
  528. );
  529. FnExit:
  530. if ( pDriveLayout != NULL ) {
  531. LocalFree( pDriveLayout );
  532. }
  533. return( dwStatus );
  534. }
  535. #if 0
  536. /****
  537. @func DWORD | RdbStartSvcOnNodes | Start the cluster service on
  538. the nodes in which you stopped the service.
  539. @parm IN LPCWSTR | lpszServiceName | Name of the service to start.
  540. @rdesc Returns a Win32 error code on failure. ERROR_SUCCESS on success.
  541. @comm This function attempts to start the service on the nodes on
  542. which it stopped the service for a restoration operation.
  543. @xref <f RdbStopSvcOnNodes>
  544. ****/
  545. DWORD
  546. RdbStartSvcOnNodes(
  547. IN LPCWSTR lpszServiceName
  548. )
  549. {
  550. SC_HANDLE hService;
  551. SC_HANDLE hSCManager;
  552. DWORD dwStatus = ERROR_SUCCESS;
  553. SERVICE_STATUS serviceStatus;
  554. WCHAR szNodeName[CS_MAX_NODE_NAME_LENGTH + 1];
  555. DWORD i;
  556. //
  557. // Chittur Subbaraman (chitturs) - 11/4/98
  558. //
  559. // Walk through the list of nodes
  560. //
  561. for ( i=0; i<dwRdbpNodeCount; i++ )
  562. {
  563. lstrcpyW( szNodeName, szRdbpNodeNameList + i *
  564. ( CS_MAX_NODE_NAME_LENGTH + 1 ) );
  565. //
  566. // Open a handle to the service control manager
  567. //
  568. hSCManager = OpenSCManager( szNodeName,
  569. NULL,
  570. SC_MANAGER_ALL_ACCESS );
  571. if ( hSCManager == NULL )
  572. {
  573. dwStatus = GetLastError();
  574. ClRtlLogPrint(LOG_UNUSUAL,
  575. "[INIT] RdbStartSvcOnNodes: Unable to open SC manager on node %1!ws!, Error = %2!d!\n",
  576. szNodeName,
  577. dwStatus);
  578. continue;
  579. }
  580. //
  581. // Open a handle to the service
  582. //
  583. hService = OpenService( hSCManager,
  584. lpszServiceName,
  585. SERVICE_ALL_ACCESS );
  586. CloseServiceHandle( hSCManager );
  587. if ( hService == NULL )
  588. {
  589. dwStatus = GetLastError();
  590. ClRtlLogPrint(LOG_UNUSUAL,
  591. "[INIT] RdbStartSvcOnNodes: Unable to open handle to %1!ws! service on node %2!ws!, Error = %3!d!\n",
  592. lpszServiceName,
  593. szNodeName,
  594. dwStatus);
  595. continue;
  596. }
  597. //
  598. // Check whether the service is already started.
  599. //
  600. if ( QueryServiceStatus( hService,
  601. &serviceStatus ) )
  602. {
  603. if ( ( serviceStatus.dwCurrentState == SERVICE_RUNNING ) ||
  604. ( serviceStatus.dwCurrentState == SERVICE_START_PENDING ) )
  605. {
  606. ClRtlLogPrint(LOG_NOISE,
  607. "[INIT] RdbStartSvcOnNodes: %1!ws! on node %2!ws! already started\n",
  608. lpszServiceName,
  609. szNodeName);
  610. CloseServiceHandle( hService );
  611. continue;
  612. }
  613. }
  614. //
  615. // Now, start the cluster service
  616. //
  617. if ( !StartService( hService,
  618. 0,
  619. NULL ) )
  620. {
  621. dwStatus = GetLastError();
  622. ClRtlLogPrint(LOG_ERROR,
  623. "[INIT] RdbStartSvcOnNodes: Unable to start cluster service on %1!ws!\n",
  624. szNodeName
  625. );
  626. } else
  627. {
  628. ClRtlLogPrint(LOG_ERROR,
  629. "[INIT] RdbStartSvcOnNodes: Cluster service started on %1!ws!\n",
  630. szNodeName
  631. );
  632. }
  633. //
  634. // And, close the current handle
  635. //
  636. CloseServiceHandle( hService );
  637. } // for
  638. //
  639. // Now free the memory
  640. //
  641. LocalFree( szRdbpNodeNameList );
  642. return( dwStatus );
  643. }
  644. #endif
  645. /****
  646. @func DWORD | RdbInitialize | This function performs the
  647. initialization steps necessary for the restore database
  648. manager. Specifically, copy the most recent checkpoint
  649. file from the backup path to the cluster directory overwriting
  650. the CLUSDB there.
  651. @rdesc Returns a Win32 error code if the operation is
  652. unsuccessful. ERROR_SUCCESS on success.
  653. @xref <f DmInitialize>
  654. ****/
  655. DWORD
  656. RdbInitialize(
  657. VOID
  658. )
  659. {
  660. HANDLE hFindFile = INVALID_HANDLE_VALUE;
  661. WIN32_FIND_DATAW FindData;
  662. DWORD dwStatus;
  663. WCHAR szDestFileName[MAX_PATH];
  664. LPWSTR szSourceFileName = NULL;
  665. LPWSTR szSourcePathName = NULL;
  666. DWORD dwLen;
  667. WIN32_FILE_ATTRIBUTE_DATA FileAttributes;
  668. LARGE_INTEGER liFileCreationTime;
  669. LARGE_INTEGER liMaxFileCreationTime;
  670. WCHAR szCheckpointFileName[MAX_PATH];
  671. WCHAR szClusterDir[MAX_PATH];
  672. LPCWSTR lpszPathName = CsDatabaseRestorePath;
  673. //
  674. // Chittur Subbaraman (chitturs) - 12/4/99
  675. //
  676. //
  677. // If there is no cluster database restore in progress, don't do anything.
  678. //
  679. if( CsDatabaseRestore == FALSE )
  680. {
  681. return( ERROR_SUCCESS );
  682. }
  683. ClRtlLogPrint(LOG_NOISE, "[INIT] RdbInitialize: Entry...\n");
  684. dwLen = lstrlenW ( lpszPathName );
  685. //
  686. // It is safer to use dynamic memory allocation for user-supplied
  687. // path since we don't want to put restrictions on the user
  688. // on the length of the path that can be supplied. However, as
  689. // far as our own destination path is concerned, it is system-dependent
  690. // and static memory allocation for that would suffice.
  691. //
  692. szSourcePathName = (LPWSTR) LocalAlloc ( LMEM_FIXED,
  693. ( dwLen + 25 ) *
  694. sizeof ( WCHAR ) );
  695. if ( szSourcePathName == NULL )
  696. {
  697. dwStatus = GetLastError();
  698. ClRtlLogPrint(LOG_UNUSUAL,
  699. "[INIT] RdbInitialize: Error %1!d! in allocating memory for %2!ws!\n",
  700. dwStatus,
  701. lpszPathName);
  702. goto FnExit;
  703. }
  704. lstrcpyW ( szSourcePathName, lpszPathName );
  705. //
  706. // If the client-supplied path is not already terminated with '\',
  707. // then add it.
  708. //
  709. if ( szSourcePathName [dwLen-1] != L'\\' )
  710. {
  711. szSourcePathName [dwLen++] = L'\\';
  712. szSourcePathName [dwLen] = L'\0';
  713. }
  714. lstrcatW ( szSourcePathName, L"CLUSBACKUP.DAT" );
  715. //
  716. // Try to find the CLUSBACKUP.DAT file in the directory
  717. //
  718. hFindFile = FindFirstFileW( szSourcePathName, &FindData );
  719. //
  720. // Reuse the source path name variable
  721. //
  722. szSourcePathName[dwLen] = L'\0';
  723. if ( hFindFile == INVALID_HANDLE_VALUE )
  724. {
  725. dwStatus = GetLastError();
  726. if ( dwStatus != ERROR_FILE_NOT_FOUND )
  727. {
  728. ClRtlLogPrint(LOG_UNUSUAL,
  729. "[INIT] RdbInitialize: Path %1!ws! unavailable, Error = %2!d!\n",
  730. szSourcePathName,
  731. dwStatus);
  732. } else
  733. {
  734. dwStatus = ERROR_DATABASE_BACKUP_CORRUPT;
  735. ClRtlLogPrint(LOG_UNUSUAL,
  736. "[INIT] RdbInitialize: Backup procedure from %1!ws! not fully"
  737. " successful, can't restore checkpoint to CLUSDB, Error = %2!d! !!!\n",
  738. szSourcePathName,
  739. dwStatus);
  740. }
  741. goto FnExit;
  742. }
  743. FindClose ( hFindFile );
  744. lstrcatW( szSourcePathName, L"chk*.tmp" );
  745. //
  746. // Try to find the first chk*.tmp file in the directory
  747. //
  748. hFindFile = FindFirstFileW( szSourcePathName, &FindData );
  749. //
  750. // Reuse the source path name variable
  751. //
  752. szSourcePathName[dwLen] = L'\0';
  753. if ( hFindFile == INVALID_HANDLE_VALUE )
  754. {
  755. dwStatus = GetLastError();
  756. ClRtlLogPrint(LOG_UNUSUAL,
  757. "[INIT] RdbInitialize: Error %2!d! in trying"
  758. "to find chk*.tmp file in path %1!ws!\r\n",
  759. szSourcePathName,
  760. dwStatus);
  761. goto FnExit;
  762. }
  763. szSourceFileName = (LPWSTR) LocalAlloc ( LMEM_FIXED,
  764. ( lstrlenW ( szSourcePathName ) + MAX_PATH ) *
  765. sizeof ( WCHAR ) );
  766. if ( szSourceFileName == NULL )
  767. {
  768. dwStatus = GetLastError();
  769. ClRtlLogPrint(LOG_UNUSUAL,
  770. "[INIT] RdbInitialize: Error %1!d! in allocating memory for source file name\n",
  771. dwStatus);
  772. goto FnExit;
  773. }
  774. dwStatus = ERROR_SUCCESS;
  775. liMaxFileCreationTime.QuadPart = 0;
  776. //
  777. // Now, find the most recent chk*.tmp file from the source path
  778. //
  779. while ( dwStatus == ERROR_SUCCESS )
  780. {
  781. if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  782. {
  783. goto skip;
  784. }
  785. lstrcpyW( szSourceFileName, szSourcePathName );
  786. lstrcatW( szSourceFileName, FindData.cFileName );
  787. if ( !GetFileAttributesExW( szSourceFileName,
  788. GetFileExInfoStandard,
  789. &FileAttributes ) )
  790. {
  791. dwStatus = GetLastError();
  792. ClRtlLogPrint(LOG_UNUSUAL, "[INIT] RdbInitialize: Error %1!d! in getting file"
  793. " attributes for %2!ws!\n",
  794. dwStatus,
  795. szSourceFileName);
  796. goto FnExit;
  797. }
  798. liFileCreationTime.HighPart = FileAttributes.ftCreationTime.dwHighDateTime;
  799. liFileCreationTime.LowPart = FileAttributes.ftCreationTime.dwLowDateTime;
  800. if ( liFileCreationTime.QuadPart > liMaxFileCreationTime.QuadPart )
  801. {
  802. liMaxFileCreationTime.QuadPart = liFileCreationTime.QuadPart;
  803. lstrcpyW( szCheckpointFileName, FindData.cFileName );
  804. }
  805. skip:
  806. if ( FindNextFileW( hFindFile, &FindData ) )
  807. {
  808. dwStatus = ERROR_SUCCESS;
  809. } else
  810. {
  811. dwStatus = GetLastError();
  812. }
  813. }
  814. if ( dwStatus == ERROR_NO_MORE_FILES )
  815. {
  816. dwStatus = ERROR_SUCCESS;
  817. } else
  818. {
  819. ClRtlLogPrint(LOG_UNUSUAL,
  820. "[INIT] RdbInitialize: FindNextFile failed, error=%1!d!\n",
  821. dwStatus);
  822. goto FnExit;
  823. }
  824. //
  825. // Get the directory where the cluster is installed
  826. //
  827. if ( ( dwStatus = ClRtlGetClusterDirectory( szClusterDir, MAX_PATH ) )
  828. != ERROR_SUCCESS )
  829. {
  830. ClRtlLogPrint(LOG_UNUSUAL,
  831. "[INIT] RdbInitialize: Error %1!d! in getting cluster dir !!!\n",
  832. dwStatus);
  833. goto FnExit;
  834. }
  835. lstrcpyW( szSourceFileName, szSourcePathName );
  836. lstrcatW( szSourceFileName, szCheckpointFileName );
  837. lstrcpyW( szDestFileName, szClusterDir );
  838. dwLen = lstrlenW( szDestFileName );
  839. if ( szDestFileName[dwLen-1] != L'\\' )
  840. {
  841. szDestFileName[dwLen++] = L'\\';
  842. szDestFileName[dwLen] = L'\0';
  843. }
  844. #ifdef OLD_WAY
  845. lstrcatW ( szDestFileName, L"CLUSDB" );
  846. #else // OLD_WAY
  847. lstrcatW ( szDestFileName, CLUSTER_DATABASE_NAME );
  848. #endif // OLD_WAY
  849. //
  850. // Set the destination file attribute to normal. Continue even
  851. // if you fail in this step because you will fail in the
  852. // copy if this error is fatal.
  853. //
  854. SetFileAttributesW( szDestFileName, FILE_ATTRIBUTE_NORMAL );
  855. //
  856. // Now try to copy the checkpoint file to CLUSDB
  857. //
  858. dwStatus = CopyFileW( szSourceFileName, szDestFileName, FALSE );
  859. if ( !dwStatus )
  860. {
  861. //
  862. // You failed in copying. Check whether you encountered a
  863. // sharing violation. If so, try unloading the cluster hive and
  864. // then retry.
  865. //
  866. dwStatus = GetLastError();
  867. if ( dwStatus == ERROR_SHARING_VIOLATION )
  868. {
  869. dwStatus = RdbpUnloadClusterHive( );
  870. if ( dwStatus == ERROR_SUCCESS )
  871. {
  872. SetFileAttributesW( szDestFileName, FILE_ATTRIBUTE_NORMAL );
  873. dwStatus = CopyFileW( szSourceFileName, szDestFileName, FALSE );
  874. if ( !dwStatus )
  875. {
  876. dwStatus = GetLastError();
  877. ClRtlLogPrint(LOG_UNUSUAL,
  878. "[INIT] RdbInitialize: Unable to copy file %1!ws! "
  879. "to %2!ws! for a second time, Error = %3!d!\n",
  880. szSourceFileName,
  881. szDestFileName,
  882. dwStatus);
  883. goto FnExit;
  884. }
  885. } else
  886. {
  887. ClRtlLogPrint(LOG_UNUSUAL,
  888. "[INIT] RdbInitialize: Unable to unload cluster hive, Error = %1!d!\n",
  889. dwStatus);
  890. goto FnExit;
  891. }
  892. } else
  893. {
  894. ClRtlLogPrint(LOG_UNUSUAL,
  895. "[INIT] RdbInitialize: Unable to copy file %1!ws! "
  896. "to %2!ws! for the first time, Error = %3!d!\n",
  897. szSourceFileName,
  898. szDestFileName,
  899. dwStatus);
  900. goto FnExit;
  901. }
  902. }
  903. //
  904. // Set the destination file attribute to normal.
  905. //
  906. if ( !SetFileAttributesW( szDestFileName, FILE_ATTRIBUTE_NORMAL ) )
  907. {
  908. dwStatus = GetLastError();
  909. ClRtlLogPrint(LOG_UNUSUAL,
  910. "[INIT] RdbInitialize: Unable to change the %1!ws! "
  911. "attributes to normal, Error = %2!d!\n",
  912. szDestFileName,
  913. dwStatus);
  914. goto FnExit;
  915. }
  916. dwStatus = ERROR_SUCCESS;
  917. FnExit:
  918. if ( hFindFile != INVALID_HANDLE_VALUE )
  919. {
  920. FindClose( hFindFile );
  921. }
  922. LocalFree( szSourcePathName );
  923. LocalFree( szSourceFileName );
  924. ClRtlLogPrint(LOG_NOISE,
  925. "[INIT] RdbInitialize: Exit with Status = %1!d!...\n",
  926. dwStatus);
  927. return( dwStatus );
  928. }
  929. /****
  930. @func DWORD | RdbpUnloadClusterHive | Unload the cluster hive
  931. @rdesc Returns a Win32 error code if the operation is
  932. unsuccessful. ERROR_SUCCESS on success.
  933. @xref <f RdbInitialize>
  934. ****/
  935. DWORD
  936. RdbpUnloadClusterHive(
  937. VOID
  938. )
  939. {
  940. BOOLEAN bWasEnabled;
  941. DWORD dwStatus;
  942. //
  943. // Chittur Subbaraman (chitturs) - 12/4/99
  944. //
  945. dwStatus = ClRtlEnableThreadPrivilege( SE_RESTORE_PRIVILEGE,
  946. &bWasEnabled );
  947. if ( dwStatus != ERROR_SUCCESS )
  948. {
  949. if ( dwStatus == STATUS_PRIVILEGE_NOT_HELD )
  950. {
  951. ClRtlLogPrint(LOG_UNUSUAL,
  952. "[INIT] RdbpUnloadClusterHive: Restore privilege not held by client\n");
  953. } else
  954. {
  955. ClRtlLogPrint(LOG_UNUSUAL,
  956. "[INIT] RdbpUnloadClusterHive: Attempt to enable restore "
  957. "privilege failed, Error = %1!d!\n",
  958. dwStatus);
  959. }
  960. goto FnExit;
  961. }
  962. dwStatus = RegUnLoadKeyW( HKEY_LOCAL_MACHINE,
  963. CLUSREG_KEYNAME_CLUSTER );
  964. ClRtlRestoreThreadPrivilege( SE_RESTORE_PRIVILEGE,
  965. bWasEnabled );
  966. FnExit:
  967. return( dwStatus );
  968. }
  969. /****
  970. @func DWORD | RdbpDeleteRestoreDbParams | Clean up the restore parameters stored
  971. under HKLM\System\CCC\Services\Clussvc\Parameters. The RestoreClusterDatabase
  972. API will also attempt to do this.
  973. @comm This function attempts clean the registry parameters for the restore database
  974. operation.
  975. @rdesc Returns a Win32 error code if the opening of the params key is unsuccessful.
  976. ERROR_SUCCESS on success.
  977. @xref <f RdbGetRestoreDbParams>
  978. ****/
  979. DWORD
  980. RdbpDeleteRestoreDbParams(
  981. VOID
  982. )
  983. {
  984. HKEY hClusSvcKey = NULL;
  985. DWORD dwStatus;
  986. //
  987. // Chittur Subbaraman (chitturs) - 08/28/2000
  988. //
  989. if( CsDatabaseRestore == FALSE )
  990. {
  991. return( ERROR_SUCCESS );
  992. }
  993. ClRtlLogPrint(LOG_NOISE, "[INIT] RdbDeleteRestoreDbParams: Entry...\n");
  994. //
  995. // Open key to SYSTEM\CurrentControlSet\Services\ClusSvc\Parameters
  996. //
  997. dwStatus = RegOpenKeyW( HKEY_LOCAL_MACHINE,
  998. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  999. &hClusSvcKey );
  1000. if( dwStatus != ERROR_SUCCESS )
  1001. {
  1002. ClRtlLogPrint(LOG_UNUSUAL,
  1003. "[INIT] RdbDeleteRestoreDbParams: Unable to open clussvc params key, error=%1!u!...\n",
  1004. dwStatus);
  1005. goto FnExit;
  1006. }
  1007. //
  1008. // Try to delete the values you set. You may fail in these steps, because all these values need
  1009. // not be present in the registry.
  1010. //
  1011. dwStatus = RegDeleteValueW( hClusSvcKey,
  1012. CLUSREG_NAME_SVC_PARAM_RESTORE_DB );
  1013. if ( ( dwStatus != ERROR_SUCCESS ) && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
  1014. {
  1015. ClRtlLogPrint(LOG_NOISE,
  1016. "[INIT] RdbDeleteRestoreDbParams: Unable to delete %2!ws! param value, error=%1!u!...\n",
  1017. dwStatus,
  1018. CLUSREG_NAME_SVC_PARAM_RESTORE_DB);
  1019. }
  1020. dwStatus = RegDeleteValueW( hClusSvcKey,
  1021. CLUSREG_NAME_SVC_PARAM_FORCE_RESTORE_DB );
  1022. if ( ( dwStatus != ERROR_SUCCESS ) && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
  1023. {
  1024. ClRtlLogPrint(LOG_NOISE,
  1025. "[INIT] RdbDeleteRestoreDbParams: Unable to delete %2!ws! param value, error=%1!u!...\n",
  1026. dwStatus,
  1027. CLUSREG_NAME_SVC_PARAM_FORCE_RESTORE_DB);
  1028. }
  1029. dwStatus = RegDeleteValueW( hClusSvcKey,
  1030. CLUSREG_NAME_SVC_PARAM_QUORUM_DRIVE_LETTER );
  1031. if ( ( dwStatus != ERROR_SUCCESS ) && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
  1032. {
  1033. ClRtlLogPrint(LOG_NOISE,
  1034. "[INIT] RdbDeleteRestoreDbParams: Unable to delete %2!ws! param value, error=%1!u!...\n",
  1035. dwStatus,
  1036. CLUSREG_NAME_SVC_PARAM_QUORUM_DRIVE_LETTER);
  1037. }
  1038. dwStatus = ERROR_SUCCESS;
  1039. FnExit:
  1040. if ( hClusSvcKey != NULL )
  1041. {
  1042. RegCloseKey( hClusSvcKey );
  1043. }
  1044. ClRtlLogPrint(LOG_NOISE, "[INIT] RdbDeleteRestoreDbParams: Exit with status=%1!u!...\n",
  1045. dwStatus);
  1046. return( dwStatus );
  1047. }