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.

424 lines
13 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CBaseClusterAction.cpp
  7. //
  8. // Description:
  9. // Contains the definition of the CBaseClusterAction class.
  10. //
  11. // Maintained By:
  12. // David Potter (DavidP) 06-MAR-2001
  13. // Vij Vasu (Vvasu) 08-MAR-2000
  14. //
  15. //////////////////////////////////////////////////////////////////////////////
  16. //////////////////////////////////////////////////////////////////////////////
  17. // Include Files
  18. //////////////////////////////////////////////////////////////////////////////
  19. // The precompiled header.
  20. #include "pch.h"
  21. // For the CBaseClusterAction class
  22. #include "CBaseClusterAction.h"
  23. // For OS version check and installation state functions.
  24. #include "clusrtl.h"
  25. // For the CEnableThreadPrivilege class.
  26. #include "CEnableThreadPrivilege.h"
  27. // For CLUSREG_INSTALL_DIR_VALUE_NAME
  28. #include "clusudef.h"
  29. //////////////////////////////////////////////////////////////////////////////
  30. // Global variables
  31. //////////////////////////////////////////////////////////////////////////////
  32. // Name of the cluster configuration semaphore.
  33. const WCHAR * g_pszConfigSemaphoreName = L"Global\\Microsoft Cluster Configuration Semaphore";
  34. //////////////////////////////////////////////////////////////////////////
  35. // Macros definitions
  36. //////////////////////////////////////////////////////////////////////////
  37. // Name of the main cluster INF file.
  38. #define CLUSTER_INF_FILE_NAME \
  39. L"ClCfgSrv.INF"
  40. //////////////////////////////////////////////////////////////////////////////
  41. //++
  42. //
  43. // CBaseClusterAction::CBaseClusterAction
  44. //
  45. // Description:
  46. // Default constructor of the CBaseClusterAction class
  47. //
  48. // Arguments:
  49. // pbcaiInterfaceIn
  50. // Pointer to the interface class for this library.
  51. //
  52. // Return Value:
  53. // None.
  54. //
  55. // Exceptions Thrown:
  56. // Any thrown by underlying functions
  57. //
  58. //--
  59. //////////////////////////////////////////////////////////////////////////////
  60. CBaseClusterAction::CBaseClusterAction( CBCAInterface * pbcaiInterfaceIn )
  61. : m_ebcaAction( eCONFIG_ACTION_NONE )
  62. , m_pbcaiInterface( pbcaiInterfaceIn )
  63. {
  64. BCATraceScope( "" );
  65. DWORD dwBufferSize = 0;
  66. UINT uiErrorLine = 0;
  67. LPBYTE pbTempPtr = NULL;
  68. DWORD dwError = ERROR_SUCCESS;
  69. SmartSz sszTemp;
  70. CRegistryKey rkInstallDirKey;
  71. //
  72. // Perform a sanity check on the parameters used by this class
  73. //
  74. if ( pbcaiInterfaceIn == NULL )
  75. {
  76. BCATraceMsg( "The pointer to the interface object is NULL. Throwing exception." );
  77. THROW_ASSERT( E_INVALIDARG, "The pointer to the interface object is NULL" );
  78. } // if: the input pointer is NULL
  79. //
  80. // Get the cluster installation directory.
  81. //
  82. m_strClusterInstallDir.Empty();
  83. // Open the registry key.
  84. rkInstallDirKey.OpenKey(
  85. HKEY_LOCAL_MACHINE
  86. , CLUSREG_KEYNAME_NODE_DATA
  87. , KEY_READ
  88. );
  89. rkInstallDirKey.QueryValue(
  90. CLUSREG_INSTALL_DIR_VALUE_NAME
  91. , &pbTempPtr
  92. , &dwBufferSize
  93. );
  94. // Memory will be freed when this function exits.
  95. sszTemp.Assign( reinterpret_cast< WCHAR * >( pbTempPtr ) );
  96. // Copy the path into the member variable.
  97. m_strClusterInstallDir = sszTemp.PMem();
  98. {
  99. // First, remove any trailing backslash characters from the quorum directory name.
  100. WCHAR rgchQuorumDirName[ sizeof( CLUS_NAME_DEFAULT_FILESPATH ) / sizeof( *CLUS_NAME_DEFAULT_FILESPATH ) ];
  101. signed int idxLastChar = sizeof( CLUS_NAME_DEFAULT_FILESPATH ) / sizeof( *CLUS_NAME_DEFAULT_FILESPATH ) - 1;
  102. wcsncpy(
  103. rgchQuorumDirName
  104. , CLUS_NAME_DEFAULT_FILESPATH
  105. , idxLastChar + 1
  106. );
  107. --idxLastChar; // idxLastChar now points to the last non-null character
  108. // Iterate till we find the last character that is not a backspace.
  109. while ( ( idxLastChar >= 0 ) && ( rgchQuorumDirName[ idxLastChar ] == L'\\' ) )
  110. {
  111. --idxLastChar;
  112. }
  113. // idxLastChar now points to the last non-backspace character. Terminate the string after this character.
  114. rgchQuorumDirName[ idxLastChar + 1 ] = L'\0';
  115. // Determine the local quorum directory.
  116. m_strLocalQuorumDir = m_strClusterInstallDir + L"\\";
  117. m_strLocalQuorumDir += rgchQuorumDirName;
  118. }
  119. LogMsg(
  120. "The cluster installation directory is '%s'. The localquorum directory is '%s'."
  121. , m_strClusterInstallDir.PszData()
  122. , m_strLocalQuorumDir.PszData()
  123. );
  124. BCATraceMsg2(
  125. "The cluster installation directory is '%s'. The localquorum directory is '%s'."
  126. , m_strClusterInstallDir.PszData()
  127. , m_strLocalQuorumDir.PszData()
  128. );
  129. //
  130. // Open the main cluster INF file.
  131. //
  132. m_strMainInfFileName = m_strClusterInstallDir + L"\\" CLUSTER_INF_FILE_NAME;
  133. m_sihMainInfFile.Assign(
  134. SetupOpenInfFile(
  135. m_strMainInfFileName.PszData()
  136. , NULL
  137. , INF_STYLE_WIN4
  138. , &uiErrorLine
  139. )
  140. );
  141. if ( m_sihMainInfFile.FIsInvalid() )
  142. {
  143. dwError = TW32( GetLastError() );
  144. LogMsg( "Could not open INF file '%s'. Error code = %#08x. Error line = %d. Cannot proceed.", m_strMainInfFileName.PszData(), dwError, uiErrorLine );
  145. BCATraceMsg3( "Could not open INF file '%s'. Error code = %#08x. Error line = %d. Throwing exception.", m_strMainInfFileName.PszData(), dwError, uiErrorLine );
  146. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_INF_FILE_OPEN );
  147. } // if: INF file could not be opened.
  148. BCATraceMsg1( "The INF file '%s' has been opened.", m_strMainInfFileName.PszData() );
  149. // Associate the cluster installation directory with the directory id CLUSTER_DIR_DIRID
  150. SetDirectoryId( m_strClusterInstallDir.PszData(), CLUSTER_DIR_DIRID );
  151. // Set the id for the local quorum directory.
  152. SetDirectoryId( m_strLocalQuorumDir.PszData(), CLUSTER_LOCALQUORUM_DIRID );
  153. //
  154. // Create a semaphore that will be used to make sure that only one commit is occurring
  155. // at a time. But do not acquire the semaphore now. It will be acquired later.
  156. //
  157. // Note that if this component is in an STA then, more than one instance of this
  158. // component may have the same thread excecuting methods when multiple configuration
  159. // sessions are started simultaneously. The way CreateMutex works, all components that
  160. // have the same thread running through them will successfully acquire the mutex.
  161. //
  162. SmartSemaphoreHandle smhConfigSemaphoreHandle(
  163. CreateSemaphore(
  164. NULL // Default security descriptor
  165. , 1 // Initial count.
  166. , 1 // Maximum count.
  167. , g_pszConfigSemaphoreName // Name of the semaphore
  168. )
  169. );
  170. // Check if creation failed.
  171. if ( smhConfigSemaphoreHandle.FIsInvalid() )
  172. {
  173. DWORD dwError = TW32( GetLastError() );
  174. LogMsg( "Semaphore '%ws' could not be created. Error %#08x. Cannot proceed.", g_pszConfigSemaphoreName, dwError );
  175. BCATraceMsg2( "Semaphore '%ws' could not be created. Error %#08x. Throwing exception.", g_pszConfigSemaphoreName, dwError );
  176. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_SEMAPHORE_CREATION );
  177. } // if: semaphore could not be created.
  178. m_sshConfigSemaphoreHandle = smhConfigSemaphoreHandle;
  179. //
  180. // Open and store the handle to the SCM. This will make life a lot easier for
  181. // other actions.
  182. //
  183. m_sscmhSCMHandle.Assign( OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ) );
  184. // Could we get the handle to the SCM?
  185. if ( m_sscmhSCMHandle.FIsInvalid() )
  186. {
  187. DWORD dwError = TW32( GetLastError() );
  188. LogMsg( "Error %#08x occurred trying get a handle to the SCM. Cannot proceed.", dwError );
  189. BCATraceMsg1( "Error %#08x occurred trying get a handle to the SCM. Throwing exception.", dwError );
  190. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_OPEN_SCM );
  191. }
  192. } //*** CBaseClusterAction::CBaseClusterAction()
  193. //////////////////////////////////////////////////////////////////////////////
  194. //++
  195. //
  196. // CBaseClusterAction::~CBaseClusterAction
  197. //
  198. // Description:
  199. // Destructor of the CBaseClusterAction class
  200. //
  201. // Arguments:
  202. // None.
  203. //
  204. // Return Value:
  205. // None.
  206. //
  207. // Exceptions Thrown:
  208. // None.
  209. //
  210. //--
  211. //////////////////////////////////////////////////////////////////////////////
  212. CBaseClusterAction::~CBaseClusterAction( void ) throw()
  213. {
  214. } //*** CBaseClusterAction::~CBaseClusterAction()
  215. //////////////////////////////////////////////////////////////////////////////
  216. //++
  217. //
  218. // void
  219. // CBaseClusterAction::Commit
  220. //
  221. // Description:
  222. // Acquires a semaphore to prevent simultaneous configuration and commits
  223. // the action list.
  224. //
  225. // Arguments:
  226. // None.
  227. //
  228. // Return Value:
  229. // None.
  230. //
  231. // Exceptions Thrown:
  232. // CAssert
  233. // If this object is not in the correct state when this function is
  234. // called.
  235. //
  236. // Any exceptions thrown by functions called.
  237. //
  238. //--
  239. //////////////////////////////////////////////////////////////////////////////
  240. void
  241. CBaseClusterAction::Commit( void )
  242. {
  243. BCATraceScope( "" );
  244. DWORD dwSemaphoreState;
  245. // Call the base class commit method.
  246. BaseClass::Commit();
  247. LogMsg( "Initiating cluster configuration." );
  248. //
  249. // Acquire the cluster configuration semaphore.
  250. // It is ok to use WaitForSingleObject() here instead of MsgWaitForMultipleObjects
  251. // since we are not blocking.
  252. //
  253. dwSemaphoreState = WaitForSingleObject( m_sshConfigSemaphoreHandle, 0 ); // zero timeout
  254. // Did we get the semaphore?
  255. if ( ( dwSemaphoreState != WAIT_ABANDONED )
  256. && ( dwSemaphoreState != WAIT_OBJECT_0 )
  257. )
  258. {
  259. DWORD dwError;
  260. if ( dwSemaphoreState == WAIT_FAILED )
  261. {
  262. dwError = TW32( GetLastError() );
  263. } // if: WaitForSingleObject failed.
  264. else
  265. {
  266. dwError = TW32( ERROR_LOCK_VIOLATION );
  267. } // else: could not get lock
  268. LogMsg( "Could not acquire configuration lock. Error %#08x. Aborting.", dwError );
  269. BCATraceMsg1( "Could not acquire configuration lock. Error %#08x. Throwing exception.", dwError );
  270. THROW_CONFIG_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_SEMAPHORE_ACQUISITION );
  271. } // if: semaphore acquisition failed
  272. // Assign the locked semaphore handle to a smart handle for safe release.
  273. SmartSemaphoreLock sslConfigSemaphoreLock( m_sshConfigSemaphoreHandle.HHandle() );
  274. BCATraceMsg( "Configuration semaphore acquired. Committing action list." );
  275. LogMsg( "The configuration lock has been acquired." );
  276. // Commit the action list.
  277. m_alActionList.Commit();
  278. } //*** CBaseClusterAction::Commit()
  279. //////////////////////////////////////////////////////////////////////////////
  280. //++
  281. //
  282. // void
  283. // CBaseClusterAction::Rollback
  284. //
  285. // Description:
  286. // Performs the rolls back of the action committed by this object.
  287. //
  288. // Arguments:
  289. // None.
  290. //
  291. // Return Value:
  292. // None.
  293. //
  294. // Exceptions Thrown:
  295. // Any exceptions thrown by functions called.
  296. //
  297. //--
  298. //////////////////////////////////////////////////////////////////////////////
  299. void
  300. CBaseClusterAction::Rollback( void )
  301. {
  302. BCATraceScope( "" );
  303. // Call the base class rollback method.
  304. BaseClass::Rollback();
  305. // Rollback the actions.
  306. m_alActionList.Rollback();
  307. } //*** CBaseClusterAction::Rollback()
  308. //////////////////////////////////////////////////////////////////////////////
  309. //++
  310. //
  311. // void
  312. // CBaseClusterAction::SetDirectoryId
  313. //
  314. // Description:
  315. // Associate a particular directory with an id in the main INF file.
  316. //
  317. // Arguments:
  318. // pcszDirectoryNameIn
  319. // The full path to the directory.
  320. //
  321. // uiIdIn
  322. // The id to associate this directory with.
  323. //
  324. // Return Value:
  325. // None.
  326. //
  327. // Exceptions Thrown:
  328. // CRuntimeError
  329. // If SetupSetDirectoryId fails.
  330. //
  331. // Remarks:
  332. // m_sihMainInfFile has to be valid before this function can be called.
  333. //--
  334. //////////////////////////////////////////////////////////////////////////////
  335. void
  336. CBaseClusterAction::SetDirectoryId(
  337. const WCHAR * pcszDirectoryNameIn
  338. , UINT uiIdIn
  339. )
  340. {
  341. if ( SetupSetDirectoryId( m_sihMainInfFile, uiIdIn, pcszDirectoryNameIn ) == FALSE )
  342. {
  343. DWORD dwError = TW32( GetLastError() );
  344. LogMsg( "Could not associate the directory '%ws' with the id %#x. Error %#08x. Cannot proceed.", pcszDirectoryNameIn, uiIdIn, dwError );
  345. BCATraceMsg3( "Could not associate the directory '%ws' with the id %#x. Error %#08x. Throwing exception.", pcszDirectoryNameIn, uiIdIn, dwError );
  346. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_SET_DIRID );
  347. } // if: there was an error setting the directory id.
  348. BCATraceMsg2( "Directory id %d associated with '%ws'.", uiIdIn, pcszDirectoryNameIn );
  349. } //*** CBaseClusterAction::SetDirectoryId()