Leaked source code of windows server 2003
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.

1230 lines
44 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998-2003 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CClusOCMApp.cpp
  7. //
  8. // Header File:
  9. // CClusOCMApp.h
  10. //
  11. // Description:
  12. // ClusOCM.DLL is an Optional Components Manager DLL for installation of
  13. // Microsoft Cluster Server. This file contains the definition of the
  14. // class ClusOCMApp, which is the main class of the ClusOCM DLL.
  15. //
  16. // Documentation:
  17. // [1] 2001 Setup - Architecture.doc
  18. // Architecture of the DLL for Whistler (Windows 2001)
  19. //
  20. // [2] 2000 Setup - FuncImpl.doc
  21. // Contains description of the previous version of this DLL (Windows 2000)
  22. //
  23. // [3] http://winweb/setup/ocmanager/OcMgr1.doc
  24. // Documentation about the OC Manager API
  25. //
  26. // Maintained By:
  27. // David Potter (DavidP) 15-AUG-2001
  28. //
  29. // Vij Vasu (Vvasu) 03-MAR-2000
  30. // Adapted for Windows Server 2003.
  31. // See documentation for more complete details. Major changes are:
  32. //
  33. // - This DLL no longer uses MFC. Class structure has changed.
  34. //
  35. // - Cluster binaries are always installed. So, uninstall functionality
  36. // has been removed from this DLL.
  37. //
  38. // - Upgrade on a computer that does not have the cluster binaries
  39. // should now install the binaries.
  40. //
  41. // - CluAdmin completely functional by the end of install of binaries.
  42. //
  43. // - Time Service no longer installed.
  44. //
  45. // - Complete change in coding and commenting style.
  46. //
  47. // C. Brent Thomas (a-brentt) 01-JAN-1998
  48. // Created the original version.
  49. //
  50. //////////////////////////////////////////////////////////////////////////////
  51. //////////////////////////////////////////////////////////////////////////////
  52. // Include Files
  53. //////////////////////////////////////////////////////////////////////////////
  54. // Precompiled header for this DLL.
  55. #include "Pch.h"
  56. // The header file for this module.
  57. #include "CClusOCMApp.h"
  58. // For the CTaskCleanInstall class
  59. #include "CTaskCleanInstall.h"
  60. // For the CTaskUpgradeNT4 class
  61. #include "CTaskUpgradeNT4.h"
  62. // For the CTaskUpgradeWindows2000 class
  63. #include "CTaskUpgradeWin2k.h"
  64. // For the CTaskUpgradeWindowsDotNet class
  65. #include "CTaskUpgradeWhistler.h"
  66. //////////////////////////////////////////////////////////////////////////////
  67. // Macro Definitions
  68. //////////////////////////////////////////////////////////////////////////////
  69. // Needed for tracing.
  70. DEFINE_THISCLASS( "CClusOCMApp" )
  71. /////////////////////////////////////////////////////////////////////////////
  72. //++
  73. //
  74. // CClusOCMApp::CClusOCMApp
  75. //
  76. // Description:
  77. // Constructor of the CClusOCMApp class.
  78. //
  79. // Arguments:
  80. // None.
  81. //
  82. // Return Value:
  83. // None.
  84. //
  85. //--
  86. /////////////////////////////////////////////////////////////////////////////
  87. CClusOCMApp::CClusOCMApp( void )
  88. : m_fIsUnattendedSetup( false )
  89. , m_fIsUpgrade( false )
  90. , m_fIsGUIModeSetup( false )
  91. , m_fAttemptedTaskCreation( false )
  92. , m_cisCurrentInstallState( eClusterInstallStateUnknown )
  93. , m_dwFirstError( NO_ERROR )
  94. {
  95. TraceFunc( "" );
  96. memset( &m_sicSetupInitComponent, 0, sizeof( m_sicSetupInitComponent ) );
  97. TraceFuncExit();
  98. } //*** CClusOCMApp::CClusOCMApp
  99. /////////////////////////////////////////////////////////////////////////////
  100. //++
  101. //
  102. // CClusOCMApp::~CClusOCMApp
  103. //
  104. // Description:
  105. // Destructor of the CClusOCMApp class.
  106. //
  107. // Arguments:
  108. // None.
  109. //
  110. // Return Value:
  111. // None.
  112. //
  113. //--
  114. /////////////////////////////////////////////////////////////////////////////
  115. CClusOCMApp::~CClusOCMApp( void )
  116. {
  117. TraceFunc( "" );
  118. TraceFuncExit();
  119. } //*** CClusOCMApp::CClusOCMApp
  120. /////////////////////////////////////////////////////////////////////////////
  121. //++
  122. //
  123. // DWORD
  124. // CClusOCMApp::DwClusOcmSetupProc
  125. //
  126. // Description:
  127. // This function is called by the entry point of this DLL, DwClusOcmSetupProc.
  128. // See document [3] in the header of this file for details.
  129. //
  130. // This function determines what actions need to be taken (upgrade, clean
  131. // install, etc., and pass control accordingly to the correct routines.
  132. //
  133. // Arguments:
  134. // LPCVOID pvComponentIdIn
  135. // Pointer to a string that uniquely identifies the component.
  136. //
  137. // LPCVOID pvSubComponentIdIn
  138. // Pointer to a string that uniquely identifies a sub-component in
  139. // the component's hiearchy.
  140. //
  141. // UINT uiFunctionCodeIn
  142. // A numeric value indicating which function is to be perfomed.
  143. // See ocmanage.h for the macro definitions.
  144. //
  145. // UINT uiParam1In
  146. // Supplies a function specific parameter.
  147. //
  148. // PVOID pvParam2Inout
  149. // Pointer to a function specific parameter (either input or output).
  150. //
  151. // Return Value:
  152. // A function specific value is returned to OC Manager.
  153. //
  154. //--
  155. /////////////////////////////////////////////////////////////////////////////
  156. DWORD
  157. CClusOCMApp::DwClusOcmSetupProc(
  158. LPCVOID pvComponentIdIn
  159. , LPCVOID pvSubComponentIdIn
  160. , UINT uiFunctionCodeIn
  161. , UINT uiParam1In
  162. , PVOID pvParam2Inout
  163. )
  164. {
  165. TraceFunc( "" );
  166. LogMsg( "Entering " __FUNCTION__ "()" );
  167. DWORD dwReturnValue = NO_ERROR;
  168. // Switch based on the function code passed in by OC Manager.
  169. switch ( uiFunctionCodeIn )
  170. {
  171. // This is the first function that OC Manager calls.
  172. case OC_PREINITIALIZE:
  173. {
  174. LogMsg( "OC Manager called OC_PREINITIALIZE." );
  175. // Return OCFLAG_UNICODE to indicate that only UNICODE is to be used.
  176. dwReturnValue = OCFLAG_UNICODE;
  177. } // case OC_PREINITIALIZE
  178. break;
  179. //
  180. // This function is called soon after the component's setup dll is
  181. // loaded. This function provides initialization information to the
  182. // dll, instructs the dll to initialize itself, and provides a
  183. // mechanism for the dll to return information to OC Manager.
  184. //
  185. case OC_INIT_COMPONENT:
  186. {
  187. LogMsg(
  188. "OC Manager called OC_INIT_COMPONENT for the component '%s'."
  189. , reinterpret_cast< LPCWSTR >( pvComponentIdIn )
  190. );
  191. dwReturnValue = TW32( DwOcInitComponentHandler( reinterpret_cast< PSETUP_INIT_COMPONENT >( pvParam2Inout ) ) );
  192. } // case OC_INIT_COMPONENT
  193. break;
  194. // Get the initial, current and final state of the component.
  195. case OC_QUERY_STATE:
  196. {
  197. LogMsg( "OC Manager called OC_QUERY_STATE." );
  198. dwReturnValue = DwOcQueryStateHandler( uiParam1In );
  199. } // case OC_QUERY_STATE
  200. break;
  201. // OC Manager is asking approval for a user selection of installation state.
  202. case OC_QUERY_CHANGE_SEL_STATE:
  203. {
  204. LogMsg( "OC Manager called OC_QUERY_CHANGE_SEL_STATE." );
  205. //
  206. // The cluster service has to be always installed. So, disallow any state
  207. // change that deselects the cluster service (by returning FALSE).
  208. //
  209. // The component has been deselected if uiParam1In is 0.
  210. if ( uiParam1In == 0 )
  211. {
  212. LogMsg( "Disallowing deselection of the Cluster Service." );
  213. dwReturnValue = FALSE;
  214. }
  215. else
  216. {
  217. LogMsg( "Allowing selection of the Cluster Service." );
  218. dwReturnValue = TRUE;
  219. }
  220. } // case OC_QUERY_CHANGE_SEL_STATE
  221. break;
  222. // Instructs the component to change to a given language if it can.
  223. case OC_SET_LANGUAGE:
  224. {
  225. LogMsg( "OC Manager called OC_SET_LANGUAGE." );
  226. dwReturnValue = SetThreadLocale( MAKELCID( PRIMARYLANGID( uiParam1In ), SORT_DEFAULT ) );
  227. } // case OC_SET_LANGUAGE
  228. break;
  229. //
  230. // Directs the component to manipulate a Setup API Disk Space List,
  231. // placing files on it or removing files from it, to mirror what will be
  232. // actually installed later via a Setup API file queue.
  233. //
  234. case OC_CALC_DISK_SPACE:
  235. {
  236. CClusOCMTask * pCurrentTask = NULL;
  237. LogMsg( "OC Manager called OC_CALC_DISK_SPACE." );
  238. dwReturnValue = TW32( DwGetCurrentTask( pCurrentTask ) );
  239. if ( dwReturnValue != NO_ERROR )
  240. {
  241. DwSetError( dwReturnValue );
  242. LogMsg( "Error %#x occurred trying to get a pointer to the current task.", dwReturnValue );
  243. break;
  244. } // if: we could not get the current task pointer
  245. if ( pCurrentTask != NULL )
  246. {
  247. dwReturnValue = TW32(
  248. pCurrentTask->DwOcCalcDiskSpace(
  249. ( uiParam1In != 0 ) // non-zero uiParam1In means "add to disk space requirements"
  250. , reinterpret_cast< HDSKSPC >( pvParam2Inout )
  251. )
  252. );
  253. // Note: Do not call DwSetError() here if the above function failed. Failure to calculate disk space
  254. // is to be expected if the binaries are not accessible at this time (for example, they are on a
  255. // network share and the credentials for this share have not been entered yet). This is not fatal and
  256. // hence should not trigger a cleanup.
  257. } // if: there is something to do
  258. else
  259. {
  260. LogMsg( "There is no task to be performed." );
  261. } // else: there is nothing to do.
  262. } // case OC_CALC_DISK_SPACE
  263. break;
  264. //
  265. // Directs the component to queue file operations for installation, based on
  266. // user interaction with the wizard pages and other component-specific factors.
  267. //
  268. case OC_QUEUE_FILE_OPS:
  269. {
  270. CClusOCMTask * pCurrentTask = NULL;
  271. LogMsg( "OC Manager called OC_QUEUE_FILE_OPS." );
  272. if ( DwGetError() != NO_ERROR )
  273. {
  274. // If an error has occurred previously, do not do this operation.
  275. LogMsg( "An error has occurred earlier in this task. Nothing will be done here." );
  276. break;
  277. } // if: an error has occurred previously
  278. dwReturnValue = TW32( DwGetCurrentTask( pCurrentTask ) );
  279. if ( dwReturnValue != NO_ERROR )
  280. {
  281. DwSetError( dwReturnValue );
  282. LogMsg( "Error %#x occurred trying to get a pointer to the current task.", dwReturnValue );
  283. break;
  284. } // if: we could not get the current task pointer
  285. if ( pCurrentTask != NULL )
  286. {
  287. dwReturnValue = TW32(
  288. DwSetError(
  289. pCurrentTask->DwOcQueueFileOps(
  290. reinterpret_cast< HSPFILEQ >( pvParam2Inout )
  291. )
  292. )
  293. );
  294. } // if: there is something to do
  295. else
  296. {
  297. LogMsg( "There is no task to be performed." );
  298. } // else: there is nothing to do.
  299. } // case OC_QUEUE_FILE_OPS
  300. break;
  301. //
  302. // Allows the component to perform any additional operations needed
  303. // to complete installation, for example registry manipulations, and
  304. // so forth.
  305. //
  306. case OC_COMPLETE_INSTALLATION:
  307. {
  308. CClusOCMTask * pCurrentTask = NULL;
  309. LogMsg( "OC Manager called OC_COMPLETE_INSTALLATION." );
  310. if ( DwGetError() != NO_ERROR )
  311. {
  312. // If an error has occurred previously, do not do this operation.
  313. LogMsg( "An error has occurred earlier in this task. Nothing will be done here." );
  314. break;
  315. } // if: an error has occurred previously
  316. dwReturnValue = TW32( DwGetCurrentTask( pCurrentTask ) );
  317. if ( dwReturnValue != NO_ERROR )
  318. {
  319. DwSetError( dwReturnValue );
  320. LogMsg( "Error %#x occurred trying to get a pointer to the current task.", dwReturnValue );
  321. break;
  322. } // if: we could not get the current task pointer
  323. if ( pCurrentTask != NULL )
  324. {
  325. dwReturnValue = TW32( DwSetError( pCurrentTask->DwOcCompleteInstallation() ) );
  326. } // if: there is something to do
  327. else
  328. {
  329. LogMsg( "There is no task to be performed." );
  330. } // else: there is nothing to do.
  331. } // case OC_COMPLETE_INSTALLATION
  332. break;
  333. //
  334. // Informs the component that it is about to be unloaded.
  335. //
  336. case OC_CLEANUP:
  337. {
  338. CClusOCMTask * pCurrentTask = NULL;
  339. LogMsg( "OC Manager called OC_CLEANUP." );
  340. dwReturnValue = TW32( DwGetCurrentTask( pCurrentTask ) );
  341. if ( dwReturnValue != NO_ERROR )
  342. {
  343. DwSetError( dwReturnValue );
  344. LogMsg( "Error %#x occurred trying to get a pointer to the current task.", dwReturnValue );
  345. break;
  346. } // if: we could not get the current task pointer
  347. if ( pCurrentTask != NULL )
  348. {
  349. dwReturnValue = TW32( DwSetError( pCurrentTask->DwOcCleanup() ) );
  350. // Once the cleanup is done, we have nothing else to do. Free the task object.
  351. ResetCurrentTask();
  352. } // if: there is something to do
  353. else
  354. {
  355. LogMsg( "There is no task to be performed." );
  356. } // else: there is nothing to do.
  357. } // case OC_CLEANUP
  358. break;
  359. default:
  360. {
  361. LogMsg( "OC Manager called unknown function. Function code is %#x.", uiFunctionCodeIn );
  362. } // case: default
  363. } // switch( uiFunctionCodeIn )
  364. LogMsg( "Return Value is %#x.", dwReturnValue );
  365. RETURN( dwReturnValue );
  366. } //*** CClusOCMApp::DwClusOcmSetupProc
  367. /////////////////////////////////////////////////////////////////////////////
  368. //++
  369. //
  370. // DWORD
  371. // CClusOCMApp::DwOcInitComponentHandler
  372. //
  373. // Description:
  374. // This function handles the OC_INIT_COMPONENT messages from the Optional
  375. // Components Manager.
  376. //
  377. // This function is called soon after the component's setup dll is
  378. // loaded. This checks OS and OC Manager versions, initializes CClusOCMApp
  379. // data members, determines the cluster service installation state, etc.
  380. //
  381. // Arguments:
  382. // PSETUP_INIT_COMPONENT pSetupInitComponentInout
  383. // Pointer to a SETUP_INIT_COMPONENT structure.
  384. //
  385. // Return Value:
  386. // NO_ERROR
  387. // Call was successful.
  388. //
  389. // ERROR_CALL_NOT_IMPLEMENTED
  390. // The OC Manager and this DLLs versions are not compatible.
  391. //
  392. // ERROR_CANCELLED
  393. // Any other error occurred. No other error codes are returned.
  394. // The actual error is logged.
  395. //
  396. // Remarks:
  397. // The SETUP_INIT_COMPONENT structure pointed to by pSetupInitComponentInout
  398. // is not persistent. It is therefore necessary to save a copy locally.
  399. //
  400. //--
  401. /////////////////////////////////////////////////////////////////////////////
  402. DWORD
  403. CClusOCMApp::DwOcInitComponentHandler(
  404. PSETUP_INIT_COMPONENT pSetupInitComponentInout
  405. )
  406. {
  407. TraceFunc( "" );
  408. LogMsg( "Entering " __FUNCTION__ "()" );
  409. DWORD dwReturnValue = NO_ERROR;
  410. UINT uiStatus;
  411. eClusterInstallState cisTempState = eClusterInstallStateUnknown;
  412. // Dummy do-while loop to avoid gotos.
  413. do
  414. {
  415. if ( pSetupInitComponentInout == NULL )
  416. {
  417. LogMsg( "Error: Pointer to the SETUP_INIT_COMPONENT structure is NULL." );
  418. dwReturnValue = TW32( ERROR_CANCELLED );
  419. break;
  420. } // if: pSetupInitComponentInout is NULL
  421. // Indicate to OC Manager which version of OC Manager this dll expects.
  422. pSetupInitComponentInout->ComponentVersion = OCMANAGER_VERSION;
  423. // Save the SETUP_INIT_COMPONENT structure.
  424. SetSetupState( *pSetupInitComponentInout );
  425. //
  426. // Determine if the OC Manager version is correct.
  427. //
  428. if ( OCMANAGER_VERSION > RsicGetSetupInitComponent().OCManagerVersion )
  429. {
  430. // Indicate failure.
  431. LogMsg(
  432. "Error: OC Manager version mismatch. Version %d is required, Version %d was reported.",
  433. OCMANAGER_VERSION,
  434. RsicGetSetupInitComponent().OCManagerVersion
  435. );
  436. dwReturnValue = TW32( ERROR_CALL_NOT_IMPLEMENTED );
  437. break;
  438. } // if: the OC Manager version is incorrect.
  439. LogMsg( "The OC Manager version matches with the version of this component." );
  440. #if 0
  441. /*
  442. // KB: 06-DEC-2000 DavidP
  443. // Since ClusOCM only copies files and registers some COM objects,
  444. // there is no longer any reason to perform an OS check. We now
  445. // depend on this happening in the service when the node is added
  446. // to a cluster.
  447. //
  448. // Check OS version and suite information.
  449. //
  450. LogMsg( "Checking if OS version and Product Suite are compatible..." );
  451. if ( ClRtlIsOSValid() == FALSE )
  452. {
  453. // The OS version and/or Product Suite are not compatible
  454. DWORD dwErrorCode = TW32( GetLastError() );
  455. LogMsg( "Cluster Service cannot be installed on this computer. The version or product suite of the operating system is incorrect." );
  456. LogMsg( "ClRtlIsOSValid failed with error code %#x.", dwErrorCode );
  457. dwReturnValue = ERROR_CANCELLED;
  458. break;
  459. } // if: OS version and/or Product Suite are not compatible
  460. LogMsg( "OS version and product suite are correct." );
  461. */
  462. #endif
  463. // Is the handle to the component INF valid?
  464. if ( ( RsicGetSetupInitComponent().ComponentInfHandle == INVALID_HANDLE_VALUE )
  465. || ( RsicGetSetupInitComponent().ComponentInfHandle == NULL )
  466. )
  467. {
  468. // Indicate failure.
  469. LogMsg( "Error: ComponentInfHandle is invalid." );
  470. dwReturnValue = TW32( ERROR_CANCELLED );
  471. break;
  472. } // if: the INF file handle is not valid.
  473. //
  474. // The following call to SetupOpenAppendInfFile ensures that layout.inf
  475. // gets appended to ClusOCM.inf. This is required for several reasons
  476. // dictated by the Setup API. In theory OC Manager should do this, but
  477. // as per Andrew Ritz, 8/24/98, OC manager neglects to do it and it is
  478. // harmless to do it here after OC Manager is revised.
  479. //
  480. // Note that passing NULL as the first parameter causes SetupOpenAppendInfFile
  481. // to append the file(s) listed on the LayoutFile entry in clusocm.inf.
  482. //
  483. // The above comment was written by Brent.
  484. // TODO: Check if this is still needed. (Vij Vasu, 05-MAR-2000)
  485. //
  486. SetupOpenAppendInfFile(
  487. NULL,
  488. RsicGetSetupInitComponent().ComponentInfHandle,
  489. &uiStatus
  490. );
  491. //
  492. // Determine the current installation state of the cluster service. This can
  493. // be done by calling the function ClRtlGetClusterInstallState.
  494. // However, on machines that are upgrading from NT4, this will not work and
  495. // the correct installation state can be found out only by checking if the
  496. // cluster service is registered (ClRtlGetClusterInstallState will return
  497. // eClusterInstallStateUnknown in this case)
  498. //
  499. dwReturnValue = ClRtlGetClusterInstallState( NULL, &cisTempState );
  500. if ( dwReturnValue != ERROR_SUCCESS )
  501. {
  502. LogMsg( "Error %#x occurred calling ClRtlGetClusterInstallState(). Cluster Service installation state cannot be determined.", dwReturnValue );
  503. dwReturnValue = TW32( ERROR_CANCELLED );
  504. break;
  505. } // if: ClRtlGetClusterInstallState failed
  506. if ( cisTempState == eClusterInstallStateUnknown )
  507. {
  508. bool fRegistered = false;
  509. dwReturnValue = TW32( DwIsClusterServiceRegistered( &fRegistered ) );
  510. if ( dwReturnValue != ERROR_SUCCESS )
  511. {
  512. LogMsg( "Error %#x: Could not check if the cluster service was registered or not.", dwReturnValue );
  513. dwReturnValue = ERROR_CANCELLED;
  514. break;
  515. }
  516. LogMsg( "ClRtlGetClusterInstallState() returned eClusterInstallStateUnknown. Trying to see if the service is registered." );
  517. if ( fRegistered )
  518. {
  519. LogMsg( "The Cluster Service is registered. Setting current installation state to eClusterInstallStateConfigured." );
  520. cisTempState = eClusterInstallStateConfigured;
  521. }
  522. else
  523. {
  524. LogMsg( "The Cluster Service is not registered." );
  525. } // else: Cluster Service is not registered.
  526. } // if: ClRtlGetClusterInstallState returned eClusterInstallStateUnknown
  527. LogMsg( "The current installation state of the cluster service is %#x.", cisTempState );
  528. // Store the current cluster installation state.
  529. CisStoreClusterInstallState( cisTempState );
  530. }
  531. while ( false ); // dummy do-while loop to avoid gotos
  532. LogMsg( "Return Value is %#x.", dwReturnValue );
  533. RETURN( dwReturnValue );
  534. } //*** CClusOCMApp::DwOcInitComponentHandler
  535. /////////////////////////////////////////////////////////////////////////////
  536. //++
  537. //
  538. // DWORD
  539. // CClusOCMApp::DwOcQueryStateHandler
  540. //
  541. // Description:
  542. // This function handles the OC_QUERY_STATE messages from the Optional
  543. // Components Manager.
  544. //
  545. // This function is called called at least thrice, once each to get the
  546. // initial, current and the final installation states.
  547. //
  548. // The initial state is the state before ClusOCM was called.
  549. //
  550. // The current state is the current selection state. This is always
  551. // 'On' because the cluster binaries are always installed.
  552. //
  553. // The final state is the state after ClusOCM has done its tasks.
  554. //
  555. // Arguments:
  556. // UINT uiSelStateQueryTypeIn
  557. // The type of query - OCSELSTATETYPE_ORIGINAL, OCSELSTATETYPE_CURRENT
  558. // or OCSELSTATETYPE_FINAL.
  559. //
  560. // Return Value:
  561. // SubcompOn
  562. // Indicates that the checkbox next to the component in the OC
  563. // Manager UI should be set.
  564. //
  565. // SubcompOff
  566. // Indicates that the checkbox should be cleared.
  567. //
  568. // SubcompUseOcManagerDefault
  569. // OC Manager should set the state of the checkbox.
  570. //
  571. // Remarks:
  572. // This function has to be called after DwOcInitComponentHandler, otherwise
  573. // the initial installation state may not be set correctly.
  574. //--
  575. /////////////////////////////////////////////////////////////////////////////
  576. DWORD
  577. CClusOCMApp::DwOcQueryStateHandler( UINT uiSelStateQueryTypeIn )
  578. {
  579. TraceFunc( "" );
  580. LogMsg( "Entering " __FUNCTION__ "()" );
  581. DWORD dwReturnValue = SubcompUseOcManagerDefault;
  582. switch( uiSelStateQueryTypeIn )
  583. {
  584. case OCSELSTATETYPE_ORIGINAL:
  585. {
  586. LogMsg( "OC Manager is querying for the original state." );
  587. //
  588. // If the cluster binaries have been installed or if cluster service
  589. // has been configured, then the original installation state is on.
  590. //
  591. dwReturnValue = ( CisGetClusterInstallState() == eClusterInstallStateUnknown )
  592. ? SubcompOff
  593. : SubcompOn;
  594. } // case: OCSELSTATETYPE_ORIGINAL
  595. break;
  596. case OCSELSTATETYPE_CURRENT:
  597. {
  598. // The current state is always on.
  599. LogMsg( "OC Manager is querying for the current state." );
  600. dwReturnValue = SubcompOn;
  601. } // case: OCSELSTATETYPE_CURRENT
  602. break;
  603. case OCSELSTATETYPE_FINAL:
  604. {
  605. LogMsg( "OC Manager is querying for the final state." );
  606. //
  607. // If we are here, then the OC_COMPLETE_INSTALLATION has already
  608. // been called. At this stage CisStoreClusterInstallState() reflects
  609. // the state after ClusOCM has done its tasks.
  610. //
  611. dwReturnValue = ( CisGetClusterInstallState() == eClusterInstallStateUnknown )
  612. ? SubcompOff
  613. : SubcompOn;
  614. } // case: OCSELSTATETYPE_FINAL
  615. break;
  616. }; // switch: based on uiSelStateQueryTypeIn
  617. LogMsg( "Return Value is %#x.", dwReturnValue );
  618. RETURN( dwReturnValue );
  619. } //*** CClusOCMApp::DwOcQueryStateHandler
  620. /////////////////////////////////////////////////////////////////////////////
  621. //++
  622. //
  623. // void
  624. // CClusOCMApp::SetSetupState
  625. //
  626. // Description:
  627. // Set the SETUP_INIT_COMPONENT structure. Use this structure and set
  628. // various setup state variables.
  629. //
  630. // Arguments:
  631. // const SETUP_INIT_COMPONENT & sicSourceIn
  632. // The source SETUP_INIT_COMPONENT structure, usually passed in by
  633. // the OC Manager.
  634. //
  635. // Return Value:
  636. // None.
  637. //
  638. //--
  639. /////////////////////////////////////////////////////////////////////////////
  640. void
  641. CClusOCMApp::SetSetupState( const SETUP_INIT_COMPONENT & sicSourceIn )
  642. {
  643. TraceFunc( "" );
  644. m_sicSetupInitComponent = sicSourceIn;
  645. m_fIsUnattendedSetup = (
  646. ( m_sicSetupInitComponent.SetupData.OperationFlags
  647. & (DWORDLONG) SETUPOP_BATCH
  648. )
  649. !=
  650. (DWORDLONG) 0L
  651. );
  652. m_fIsUpgrade = (
  653. ( m_sicSetupInitComponent.SetupData.OperationFlags
  654. & (DWORDLONG) SETUPOP_NTUPGRADE
  655. )
  656. !=
  657. (DWORDLONG) 0L
  658. );
  659. m_fIsGUIModeSetup = (
  660. ( m_sicSetupInitComponent.SetupData.OperationFlags
  661. & (DWORDLONG) SETUPOP_STANDALONE
  662. )
  663. ==
  664. (DWORDLONG) 0L
  665. );
  666. // Log setup state.
  667. LogMsg(
  668. "This is an %s, %s setup session. This is%s an upgrade."
  669. , FIsUnattendedSetup() ? L"unattended" : L"attended"
  670. , FIsGUIModeSetup() ? L"GUI mode" : L"standalone"
  671. , FIsUpgrade() ? L"" : L" not"
  672. );
  673. TraceFuncExit();
  674. } //*** CClusOCMApp::SetSetupState
  675. /////////////////////////////////////////////////////////////////////////////
  676. //++
  677. //
  678. // DWORD
  679. // CClusOCMApp::DwIsClusterServiceRegistered
  680. //
  681. // Description:
  682. // This function determines whether the Cluster Service has been registered
  683. // with the Service Control Manager. If it is, it means that it has already
  684. // been configured. This check is required in nodes being upgraded from NT4
  685. // where ClRtlGetClusterInstallState() will not work.
  686. //
  687. // Arguments:
  688. // bool * pfIsRegisteredOut
  689. // If true, Cluster Service (ClusSvc) is registered with the Service
  690. // Control Manager (SCM). Else, Cluster Service (ClusSvc) is not
  691. // registered with SCM
  692. //
  693. // Return Value:
  694. // ERROR_SUCCESS if all went well.
  695. // Other Win32 error codes on failure.
  696. //
  697. //--
  698. /////////////////////////////////////////////////////////////////////////////
  699. DWORD
  700. CClusOCMApp::DwIsClusterServiceRegistered( bool * pfIsRegisteredOut ) const
  701. {
  702. TraceFunc( "" );
  703. LogMsg( "Entering " __FUNCTION__ "()" );
  704. bool fIsRegistered = false;
  705. DWORD dwReturnValue = ERROR_SUCCESS;
  706. // dummy do-while loop to avoid gotos
  707. do
  708. {
  709. // Connect to the Service Control Manager
  710. SmartServiceHandle shServiceMgr( OpenSCManager( NULL, NULL, GENERIC_READ ) );
  711. // Was the service control manager database opened successfully?
  712. if ( shServiceMgr.HHandle() == NULL )
  713. {
  714. dwReturnValue = TW32( GetLastError() );
  715. LogMsg( "Error %#x occurred trying to open a connection to the local service control manager.", dwReturnValue );
  716. break;
  717. } // if: opening the SCM was unsuccessful
  718. // Open a handle to the Cluster Service.
  719. SmartServiceHandle shService( OpenService( shServiceMgr, L"ClusSvc", GENERIC_READ ) );
  720. // Was the handle to the service opened?
  721. if ( shService.HHandle() != NULL )
  722. {
  723. LogMsg( "The cluster service is registered." );
  724. fIsRegistered = true;
  725. break;
  726. } // if: handle to clussvc could be opened
  727. dwReturnValue = GetLastError();
  728. if ( dwReturnValue == ERROR_SERVICE_DOES_NOT_EXIST )
  729. {
  730. dwReturnValue = ERROR_SUCCESS;
  731. LogMsg( "ClusSvc does not exist as a service." );
  732. break;
  733. } // if: the handle could not be opened because the service did not exist.
  734. // Some error occurred.
  735. TW32( dwReturnValue);
  736. LogMsg( "Error %#x occurred trying to open a handle to the cluster service.", dwReturnValue );
  737. // Handles are closed by the CSmartHandle destructor.
  738. }
  739. while ( false ); // dummy do-while loop to avoid gotos
  740. if ( pfIsRegisteredOut != NULL )
  741. {
  742. *pfIsRegisteredOut = fIsRegistered;
  743. }
  744. LogMsg( "fIsRegistered is %d. Return Value is %#x.", fIsRegistered, dwReturnValue );
  745. RETURN( dwReturnValue );
  746. } //*** CClusOCMApp::DwIsClusterServiceRegistered
  747. /////////////////////////////////////////////////////////////////////////////
  748. //++
  749. //
  750. // DWORD
  751. // CClusOCMApp::DwGetCurrentTask
  752. //
  753. // Description:
  754. // This function returns a pointer to the current task object. If a task
  755. // object has not been created yet, it creates the appropriate task.
  756. //
  757. // Arguments:
  758. // CClusOCMTask *& rpTaskOut
  759. // Reference to the pointer to the current task. Do not try to
  760. // free this memory.
  761. //
  762. // If no task needs to be performed, a NULL pointer is returned.
  763. //
  764. // Return Value:
  765. // NO_ERROR if all went well.
  766. // Other Win32 error codes on failure.
  767. //
  768. //
  769. // Remarks:
  770. // This function will work properly only after the member variables which
  771. // indicate which task will be performed have been initialized correctly.
  772. //--
  773. /////////////////////////////////////////////////////////////////////////////
  774. DWORD
  775. CClusOCMApp::DwGetCurrentTask( CClusOCMTask *& rpTaskOut )
  776. {
  777. TraceFunc( "" );
  778. LogMsg( "Entering " __FUNCTION__ "()" );
  779. DWORD dwReturnValue = NO_ERROR;
  780. // Initialize the output.
  781. rpTaskOut = NULL;
  782. do
  783. {
  784. eClusterInstallState ecisCurrentState;
  785. if ( m_fAttemptedTaskCreation )
  786. {
  787. // A task object already exists - just return it.
  788. LogMsg( "A task object already exists. Returning it." );
  789. rpTaskOut = m_sptaskCurrentTask.PMem();
  790. break;
  791. } // if: the task object has already been created.
  792. LogMsg( "Creating a new task object." );
  793. // Make note of the fact that we have started our attempt to create a task object.
  794. m_fAttemptedTaskCreation = true;
  795. // Reset the task pointer.
  796. m_sptaskCurrentTask.Assign( NULL );
  797. // Get the current installation state to deduce what operation to perform.
  798. ecisCurrentState = CisGetClusterInstallState();
  799. // The task object has not been created yet - create one now.
  800. if ( ( ecisCurrentState == eClusterInstallStateUnknown ) || ( ecisCurrentState == eClusterInstallStateFilesCopied ) )
  801. {
  802. LogMsg( "The cluster installation state is %ws. Assuming that a clean install is required."
  803. , ( ( ecisCurrentState == eClusterInstallStateUnknown ) ? L"not known" : L"files copied" ) );
  804. // If the installation state is unknown, assume that the cluster binaries
  805. // are not installed.
  806. rpTaskOut = new CTaskCleanInstall( *this );
  807. if ( rpTaskOut == NULL )
  808. {
  809. LogMsg( "Error: There was not enough memory to start a clean install." );
  810. dwReturnValue = TW32( ERROR_NOT_ENOUGH_MEMORY );
  811. break;
  812. } // if: memory allocation failed
  813. } // if: the cluster installation state is eClusterInstallStateUnknown or eClusterInstallStateFilesCopied
  814. else if ( m_fIsUpgrade )
  815. {
  816. //
  817. // If we are here, it means that an upgrade is in progress and the cluster binaries
  818. // have already been installed on the OS being upgraded. Additionally, this node may
  819. // already be part of a cluster.
  820. //
  821. DWORD dwNodeClusterMajorVersion = 0;
  822. // Find out which version of the cluster service we are upgrading.
  823. dwReturnValue = TW32( DwGetNodeClusterMajorVersion( dwNodeClusterMajorVersion ) );
  824. if ( dwReturnValue != NO_ERROR )
  825. {
  826. LogMsg( "Error %#x occurred trying to determine the version of the cluster service that we are upgrading.", dwReturnValue );
  827. break;
  828. } // if: an error occurred trying to determine the version of the cluster service that we are upgrading
  829. // Check if the returned cluster version is valid
  830. if ( ( dwNodeClusterMajorVersion != NT51_MAJOR_VERSION )
  831. && ( dwNodeClusterMajorVersion != NT5_MAJOR_VERSION )
  832. && ( dwNodeClusterMajorVersion != NT4SP4_MAJOR_VERSION )
  833. && ( dwNodeClusterMajorVersion != NT4_MAJOR_VERSION )
  834. )
  835. {
  836. LogMsg( "The version of the cluster service before the upgrade (%d) is invalid.", dwNodeClusterMajorVersion );
  837. break;
  838. } // if: the cluster version is not valid
  839. // Based on the previous version of the cluster service, create the correct task object.
  840. if ( dwNodeClusterMajorVersion == NT5_MAJOR_VERSION )
  841. {
  842. LogMsg( "We are upgrading a Windows 2000 node." );
  843. rpTaskOut = new CTaskUpgradeWindows2000( *this );
  844. } // if: we are upgrading from Windows 2000
  845. else if ( dwNodeClusterMajorVersion == NT51_MAJOR_VERSION )
  846. {
  847. LogMsg( "We are upgrading a Windows Server 2003 node." );
  848. rpTaskOut = new CTaskUpgradeWindowsDotNet( *this );
  849. } // else if: we are upgrading from Windows Server 2003
  850. else
  851. {
  852. LogMsg( "We are upgrading an NT4 node." );
  853. rpTaskOut = new CTaskUpgradeNT4( *this );
  854. } // else: we are upgrading from NT4 (either SP3 or SP4)
  855. if ( rpTaskOut == NULL )
  856. {
  857. LogMsg( "Error: There was not enough memory to create the required task." );
  858. dwReturnValue = TW32( ERROR_NOT_ENOUGH_MEMORY );
  859. break;
  860. } // if: memory allocation failed
  861. } // else if: an upgrade is in progress
  862. if ( rpTaskOut != NULL )
  863. {
  864. LogMsg( "A task object was successfully created." );
  865. // Store the pointer to the newly created task in the member variable.
  866. m_sptaskCurrentTask.Assign( rpTaskOut );
  867. } // if: the task object was successfully created
  868. else
  869. {
  870. LogMsg( "No task object was created." );
  871. } // else: no task object was created
  872. }
  873. while( false ); // dummy do-while loop to avoid gotos
  874. LogMsg( "Return Value is %#x.", dwReturnValue );
  875. RETURN( dwReturnValue );
  876. } //*** CClusOCMApp::DwGetCurrentTask
  877. /////////////////////////////////////////////////////////////////////////////
  878. //++
  879. //
  880. // DWORD
  881. // CClusOCMApp::DwGetNodeClusterMajorVersion
  882. //
  883. // Description:
  884. // This function returns the major version of the cluster service that
  885. // we are upgrading. The version that this function returns is the version
  886. // of the service before the upgrade. If there was a problem reading this
  887. // information, this function lies and says that the previous version was
  888. // NT4, since this is the safest thing to say and is better than aborting
  889. // the upgrade.
  890. //
  891. // Note: This function can only be called during an upgrade.
  892. //
  893. // Arguments:
  894. // DWORD & rdwNodeClusterMajorVersionOut
  895. // Reference to DWORD that will hold the major version of the cluster
  896. // service that we are upgrading.
  897. //
  898. // Return Value:
  899. // NO_ERROR if all went well.
  900. // ERROR_NODE_NOT_AVAILABLE if an upgrade is not in progress.
  901. // ERROR_CLUSTER_INCOMPATIBLE_VERSIONS if the node is not NT4, Windows
  902. // 2000, or Windows Server 2003.
  903. // Other Win32 error codes on failure.
  904. //
  905. //
  906. // Remarks:
  907. // This function will work properly only after the member variables which
  908. // indicate which task will be performed have been initialized correctly.
  909. //--
  910. /////////////////////////////////////////////////////////////////////////////
  911. DWORD
  912. CClusOCMApp::DwGetNodeClusterMajorVersion( DWORD & rdwNodeClusterMajorVersionOut )
  913. {
  914. TraceFunc( "" );
  915. LogMsg( "Entering " __FUNCTION__ "()" );
  916. DWORD dwReturnValue = NO_ERROR;
  917. DWORD dwPrevOSMajorVersion = 0;
  918. DWORD dwPrevOSMinorVersion = 0;
  919. do
  920. {
  921. SmartRegistryKey srkOSInfoKey;
  922. DWORD dwRegValueType = 0;
  923. DWORD cbBufferSize = 0;
  924. // Initialize the output.
  925. rdwNodeClusterMajorVersionOut = 0;
  926. if ( !m_fIsUpgrade )
  927. {
  928. LogMsg( "Error: This function cannot be called when an upgrade is not in progress." );
  929. dwReturnValue = TW32( ERROR_NODE_NOT_AVAILABLE );
  930. break;
  931. } // if: an upgrade is not in progress
  932. //
  933. // Read the registry to get what the OS version was before the upgrade.
  934. // This information was written here by ClusComp.dll. From the OS version information,
  935. // try and deduce the cluster version info.
  936. // NOTE: At this point, it is not possible to differentiate between NT4_MAJOR_VERSION
  937. // and NT4SP4_MAJOR_VERSION, and, for the purposes of the upgrade, I don't think we need
  938. // to either - so, just treat all NT4 cluster nodes the same.
  939. //
  940. {
  941. HKEY hTempKey = NULL;
  942. // Open the node version info registry key
  943. dwReturnValue = TW32(
  944. RegOpenKeyEx(
  945. HKEY_LOCAL_MACHINE
  946. , CLUSREG_KEYNAME_NODE_DATA L"\\" CLUSREG_KEYNAME_PREV_OS_INFO
  947. , 0
  948. , KEY_READ
  949. , &hTempKey
  950. )
  951. );
  952. if ( dwReturnValue != ERROR_SUCCESS )
  953. {
  954. LogMsg( "Error %#x occurred trying open the registry key where where info about the previous OS is stored.", dwReturnValue );
  955. break;
  956. } // if: RegOpenKeyEx() failed
  957. // Store the opened key in a smart pointer for automatic close.
  958. srkOSInfoKey.Assign( hTempKey );
  959. }
  960. // Read the OS major version
  961. cbBufferSize = sizeof( dwPrevOSMajorVersion );
  962. dwReturnValue = TW32(
  963. RegQueryValueExW(
  964. srkOSInfoKey.HHandle()
  965. , CLUSREG_NAME_NODE_MAJOR_VERSION
  966. , 0
  967. , &dwRegValueType
  968. , reinterpret_cast< LPBYTE >( &dwPrevOSMajorVersion )
  969. , &cbBufferSize
  970. )
  971. );
  972. Assert( dwRegValueType == REG_DWORD );
  973. if ( dwReturnValue != ERROR_SUCCESS )
  974. {
  975. LogMsg( "Error %#x occurred trying to read the previous OS major version info.", dwReturnValue );
  976. break;
  977. } // if: RegQueryValueEx() failed while reading dwPrevOSMajorVersion
  978. // Read the OS minor version
  979. cbBufferSize = sizeof( dwPrevOSMinorVersion );
  980. dwReturnValue = TW32(
  981. RegQueryValueExW(
  982. srkOSInfoKey.HHandle()
  983. , CLUSREG_NAME_NODE_MINOR_VERSION
  984. , 0
  985. , &dwRegValueType
  986. , reinterpret_cast< LPBYTE >( &dwPrevOSMinorVersion )
  987. , &cbBufferSize
  988. )
  989. );
  990. Assert( dwRegValueType == REG_DWORD );
  991. if ( dwReturnValue != ERROR_SUCCESS )
  992. {
  993. LogMsg( "Error %#x occurred trying to read the previous OS minor version info.", dwReturnValue );
  994. break;
  995. } // if: RegQueryValueEx() failed while reading dwPrevOSMinorVersion
  996. LogMsg( "Previous OS major and minor versions were %d and %d respectively.", dwPrevOSMajorVersion, dwPrevOSMinorVersion );
  997. }
  998. while( false ); // dummy do-while loop to avoid gotos
  999. if ( dwReturnValue != NO_ERROR )
  1000. {
  1001. LogMsg( "An error occurred trying to read the version information of the previous OS. Proceeding assuming that it was NT4." );
  1002. dwReturnValue = NO_ERROR;
  1003. rdwNodeClusterMajorVersionOut = NT4_MAJOR_VERSION;
  1004. } // if: an error occurred trying to determine the previous OS version
  1005. else
  1006. {
  1007. if ( dwPrevOSMajorVersion == 4 )
  1008. {
  1009. // The previous OS version was NT4 (it does not matter if it was SP3 or SP4 - we will treat
  1010. // both the same way.
  1011. LogMsg( "The previous OS was NT4. We are going to treat NT4SP3 and NT4SP4 nodes the same way for upgrades." );
  1012. rdwNodeClusterMajorVersionOut = NT4_MAJOR_VERSION;
  1013. } // if: the previous OS version was NT4
  1014. else if ( dwPrevOSMajorVersion == 5 )
  1015. {
  1016. if ( dwPrevOSMinorVersion == 0 )
  1017. {
  1018. LogMsg( "The previous OS was Windows 2000." );
  1019. rdwNodeClusterMajorVersionOut = NT5_MAJOR_VERSION;
  1020. } // if: this was a Windows 2000 node
  1021. else if ( dwPrevOSMinorVersion >= 1 )
  1022. {
  1023. LogMsg( "The previous OS was Windows Server 2003." );
  1024. rdwNodeClusterMajorVersionOut = NT51_MAJOR_VERSION;
  1025. } // else if: this was a Windows Server 2003 node
  1026. else
  1027. {
  1028. LogMsg( "The previous OS was neither Windows NT 4.0, Windows 2000, nor Windows Server 2003. An error must have occurred." );
  1029. dwReturnValue = TW32( ERROR_CLUSTER_INCOMPATIBLE_VERSIONS );
  1030. } // else: the previous OS was neither NT4, Windows 2000 nor Windows Server 2003
  1031. } // else if: the previous OS major version is 5
  1032. else
  1033. {
  1034. LogMsg( "The previous OS was neither Windows NT 4.0, Windows 2000, nor Windows Server 2003. An error must have occurred." );
  1035. dwReturnValue = TW32( ERROR_CLUSTER_INCOMPATIBLE_VERSIONS );
  1036. } // else: the previous OS was neither NT4, Windows 2000 nor Windows Server 2003
  1037. } // if; we read the previous OS version info
  1038. LogMsg( "Return Value is %#x.", dwReturnValue );
  1039. RETURN( dwReturnValue );
  1040. } //*** CClusOCMApp::DwGetNodeClusterMajorVersion