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.

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