mirror of https://github.com/tongzx/nt5src
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
1197 lines
37 KiB
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
restore.c
|
|
|
|
Abstract:
|
|
|
|
Functions supporting the restoration of the cluster database
|
|
to the quorum disk
|
|
|
|
Author:
|
|
|
|
Chittur Subbaraman (chitturs) 27-Oct-1998
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "initp.h"
|
|
#include "winioctl.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
//
|
|
// Static global variables used only in this file
|
|
//
|
|
// static LPWSTR szRdbpNodeNameList = NULL;
|
|
// static DWORD dwRdbpNodeCount = 0;
|
|
|
|
/****
|
|
@func DWORD | RdbStopSvcOnNodes | Stop the requested service
|
|
on the given node list
|
|
|
|
@parm IN PNM_NODE_ENUM2 | pNodeEnum | Pointer to the list of
|
|
nodes in which the requested service has to be stopped.
|
|
|
|
@rdesc Returns a Win32 error code on failure. ERROR_SUCCESS on success.
|
|
|
|
@comm This function attempts to stop the chosen service on the chosen
|
|
list of nodes. If it fails in stopping the service on any
|
|
one of the nodes, it returns a Win32 error code.
|
|
|
|
At this time, this function DOES NOT STOP a cluster service
|
|
which is run as a process in a remote node.
|
|
|
|
@xref <f RdbStartSvcOnNodes>
|
|
****/
|
|
DWORD
|
|
RdbStopSvcOnNodes(
|
|
IN PNM_NODE_ENUM2 pNodeEnum,
|
|
IN LPCWSTR lpszServiceName
|
|
)
|
|
{
|
|
SC_HANDLE hService;
|
|
SC_HANDLE hSCManager;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
DWORD dwRetryTime;
|
|
DWORD dwRetryTick;
|
|
SERVICE_STATUS serviceStatus;
|
|
WCHAR szNodeName[CS_MAX_NODE_NAME_LENGTH + 1];
|
|
DWORD i;
|
|
BOOL bStopCommandGiven;
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 10/30/98
|
|
//
|
|
#if 0
|
|
//
|
|
// Allocate storage for the node names which you would use to
|
|
// start the service later. Memory is freed in RdbpStartSvcOnNodes
|
|
//
|
|
if ( pNodeEnum->NodeCount > 0 )
|
|
{
|
|
szRdbpNodeNameList = ( LPWSTR ) LocalAlloc( LMEM_FIXED,
|
|
sizeof ( WCHAR) *
|
|
( CS_MAX_NODE_NAME_LENGTH + 1 ) *
|
|
pNodeEnum->NodeCount );
|
|
if ( szRdbpNodeNameList == NULL )
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbStopSvcOnNodes: Unable to allocate memory for node names, Error = %1!d!\n",
|
|
GetLastError());
|
|
}
|
|
}
|
|
#endif
|
|
//
|
|
// Walk through the list of nodes
|
|
//
|
|
for ( i=0; i<pNodeEnum->NodeCount; i++ )
|
|
{
|
|
lstrcpyW( szNodeName, pNodeEnum->NodeList[i].NodeName );
|
|
//
|
|
// Skip the local node, if it is included in the list
|
|
//
|
|
if ( ( lstrcmpW ( szNodeName, NmLocalNodeName ) == 0 ) )
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
// Try for 2 minutes max to stop the service on a node. Retry
|
|
// in steps of 5 secs.
|
|
//
|
|
dwRetryTime = 120 * 1000;
|
|
dwRetryTick = 05 * 1000;
|
|
|
|
//
|
|
// Open a handle to the service control manager
|
|
//
|
|
hSCManager = OpenSCManager( szNodeName,
|
|
NULL,
|
|
SC_MANAGER_ALL_ACCESS );
|
|
if ( hSCManager == NULL )
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbStopSvcOnNodes: Unable to open SC manager on node %1!ws!, Error = %2!d!\n",
|
|
szNodeName,
|
|
dwStatus);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Open a handle to the service
|
|
//
|
|
hService = OpenService( hSCManager,
|
|
lpszServiceName,
|
|
SERVICE_ALL_ACCESS );
|
|
|
|
CloseServiceHandle( hSCManager );
|
|
|
|
if ( hService == NULL )
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbStopSvcOnNodes: Unable to open handle to %1!ws! service on node %2!ws!, Error = %3!d!\n",
|
|
lpszServiceName,
|
|
szNodeName,
|
|
dwStatus);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check whether the service is already in the SERVICE_STOPPED
|
|
// state.
|
|
//
|
|
if ( QueryServiceStatus( hService,
|
|
&serviceStatus ) )
|
|
{
|
|
if ( serviceStatus.dwCurrentState == SERVICE_STOPPED )
|
|
{
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbStopSvcOnNodes: %1!ws! on node %2!ws! already stopped\n",
|
|
lpszServiceName,
|
|
szNodeName);
|
|
CloseServiceHandle( hService );
|
|
continue;
|
|
}
|
|
}
|
|
|
|
bStopCommandGiven = FALSE;
|
|
|
|
while ( TRUE )
|
|
{
|
|
dwStatus = ERROR_SUCCESS;
|
|
if ( bStopCommandGiven == TRUE )
|
|
{
|
|
if ( QueryServiceStatus( hService,
|
|
&serviceStatus ) )
|
|
{
|
|
if ( serviceStatus.dwCurrentState == SERVICE_STOPPED )
|
|
{
|
|
//
|
|
// Succeeded in stopping the service
|
|
//
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbStopSvcOnNodes: %1!ws! on node %2!ws! stopped successfully\n",
|
|
lpszServiceName,
|
|
szNodeName);
|
|
break;
|
|
}
|
|
} else
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"[INIT] RdbStopSvcOnNodes: Error %3!d! in querying status of %1!ws! on node %2!ws!\n",
|
|
lpszServiceName,
|
|
szNodeName,
|
|
dwStatus);
|
|
}
|
|
} else
|
|
{
|
|
if ( ControlService( hService,
|
|
SERVICE_CONTROL_STOP,
|
|
&serviceStatus ) )
|
|
{
|
|
bStopCommandGiven = TRUE;
|
|
dwStatus = ERROR_SUCCESS;
|
|
} else
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"[INIT] RdbStopSvcOnNodes: Error %3!d! in trying to stop %1!ws! on node %2!ws!\n",
|
|
lpszServiceName,
|
|
szNodeName,
|
|
dwStatus);
|
|
}
|
|
}
|
|
|
|
if ( ( dwStatus == ERROR_EXCEPTION_IN_SERVICE ) ||
|
|
( dwStatus == ERROR_PROCESS_ABORTED ) ||
|
|
( dwStatus == ERROR_SERVICE_NOT_ACTIVE ) )
|
|
{
|
|
//
|
|
// The service is essentially in a terminated state
|
|
//
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbStopSvcOnNodes: %1!ws! on node %2!ws! died/inactive\n",
|
|
lpszServiceName,
|
|
szNodeName);
|
|
dwStatus = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
if ( ( dwRetryTime -= dwRetryTick ) <= 0 )
|
|
{
|
|
//
|
|
// All tries to stop the service failed, exit from this
|
|
// function with an error code
|
|
//
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbStopSvcOnNodes: Service %1!ws! service on node %2!ws! did not stop, giving up...\n",
|
|
lpszServiceName,
|
|
szNodeName);
|
|
dwStatus = ERROR_TIMEOUT;
|
|
break;
|
|
}
|
|
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbStopSvcOnNodes: Trying to stop %1!ws! on node %2!ws!\n",
|
|
lpszServiceName,
|
|
szNodeName);
|
|
//
|
|
// Sleep for a while and retry stopping the service
|
|
//
|
|
Sleep( dwRetryTick );
|
|
} // while
|
|
|
|
CloseServiceHandle( hService );
|
|
|
|
if ( dwStatus != ERROR_SUCCESS )
|
|
{
|
|
goto FnExit;
|
|
}
|
|
#if 0
|
|
//
|
|
// Save the node name for later use when starting the service
|
|
//
|
|
if ( szRdbpNodeNameList != NULL )
|
|
{
|
|
lstrcpyW( szRdbpNodeNameList + dwRdbpNodeCount *
|
|
( CS_MAX_NODE_NAME_LENGTH + 1 ),
|
|
szNodeName );
|
|
dwRdbpNodeCount++;
|
|
}
|
|
#endif
|
|
} // for
|
|
|
|
FnExit:
|
|
return( dwStatus );
|
|
}
|
|
|
|
/****
|
|
@func DWORD | RdbGetRestoreDbParams | Check the registry and see
|
|
whether the restore database option is set. If so, get the
|
|
params.
|
|
|
|
@parm IN HKEY | hKey | Handle to the cluster service parameters key
|
|
|
|
@comm This function attempts read the registry and return the
|
|
parameters for the restore database operation.
|
|
|
|
@xref <f CspGetServiceParams>
|
|
****/
|
|
VOID
|
|
RdbGetRestoreDbParams(
|
|
IN HKEY hClusSvcKey
|
|
)
|
|
{
|
|
DWORD dwLength = 0;
|
|
DWORD dwType;
|
|
DWORD dwStatus;
|
|
DWORD dwForceDatabaseRestore;
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 10/30/98
|
|
//
|
|
if ( hClusSvcKey == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Try to query the clussvc parameters key. If the RestoreDatabase
|
|
// value is present, then get the length of the restore database
|
|
// path.
|
|
//
|
|
if ( ClRtlRegQueryString( hClusSvcKey,
|
|
CLUSREG_NAME_SVC_PARAM_RESTORE_DB,
|
|
REG_SZ,
|
|
&CsDatabaseRestorePath,
|
|
&dwLength,
|
|
&dwLength ) != ERROR_SUCCESS )
|
|
{
|
|
goto FnExit;
|
|
}
|
|
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbGetRestoreDbparams: Restore Cluster Database is in progress...\n");
|
|
|
|
CsDatabaseRestore = TRUE;
|
|
|
|
//
|
|
// Try to query the clussvc parameters key for the ForceRestoreDatabase
|
|
// value. Don't bother to delete the param, since the
|
|
// RestoreClusterDatabase API will do it.
|
|
//
|
|
if ( ClRtlRegQueryDword( hClusSvcKey,
|
|
CLUSREG_NAME_SVC_PARAM_FORCE_RESTORE_DB,
|
|
&dwForceDatabaseRestore,
|
|
NULL ) != ERROR_SUCCESS )
|
|
{
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbGetRestoreDbparams: ForceRestoreDatabase params key is absent or unreadable\n"
|
|
);
|
|
goto FnExit;
|
|
}
|
|
|
|
CsForceDatabaseRestore = TRUE;
|
|
|
|
//
|
|
// Try to query the clussvc parameters key for the NewQuorumDriveLetter
|
|
// value. Check for the validity of the drive letter later when
|
|
// you attempt to fix up stuff.
|
|
//
|
|
dwLength = 0;
|
|
if ( ClRtlRegQueryString( hClusSvcKey,
|
|
CLUSREG_NAME_SVC_PARAM_QUORUM_DRIVE_LETTER,
|
|
REG_SZ,
|
|
&CsQuorumDriveLetter,
|
|
&dwLength,
|
|
&dwLength ) != ERROR_SUCCESS )
|
|
{
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbGetRestoreDbparams: NewQuorumDriveLetter params key is absent or unreadable\n"
|
|
);
|
|
}
|
|
|
|
FnExit:
|
|
//
|
|
// Make sure you delete these registry values read above. It is OK if you fail in finding
|
|
// some of these values. Note that the RestoreClusterDatabase API will also try to clean
|
|
// up these values. We cannot assume that the API will clean up these values since the
|
|
// values could be set by (a) ASR (b) A user by hand, and not always by the API.
|
|
//
|
|
RdbpDeleteRestoreDbParams();
|
|
}
|
|
|
|
/****
|
|
@func DWORD | RdbFixupQuorumDiskSignature | Fixup the quorum disk
|
|
signature with the supplied value, if necessary
|
|
|
|
@parm IN DWORD | dwSignature | The new signature which must be
|
|
written to the quorum disk.
|
|
|
|
@rdesc Returns a non-zero value if successful. 0 on failure.
|
|
|
|
@comm This function attempts to write the given signature into
|
|
the physical quorum disk, if necessary.
|
|
|
|
@xref <f RdbStartSvcOnNodes>
|
|
****/
|
|
BOOL
|
|
RdbFixupQuorumDiskSignature(
|
|
IN DWORD dwSignature
|
|
)
|
|
{
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
DWORD dwStatus;
|
|
BOOL bStatus = 1;
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 10/30/98
|
|
//
|
|
if ( ( dwSignature == 0 ) ||
|
|
( lstrlenW ( CsQuorumDriveLetter ) != 2 ) ||
|
|
( !iswalpha( CsQuorumDriveLetter[0] ) ) ||
|
|
( CsQuorumDriveLetter[1] != L':' ) )
|
|
{
|
|
bStatus = 0;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Now try to open the quorum disk device
|
|
//
|
|
if ( ( dwStatus = RdbpOpenDiskDevice ( CsQuorumDriveLetter, &hFile ) )
|
|
!= ERROR_SUCCESS )
|
|
{
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"[INIT] RdbFixupQuorumDiskSignature: Error %1!d! in opening %2!ws!\n",
|
|
dwStatus,
|
|
CsQuorumDriveLetter
|
|
);
|
|
bStatus = 0;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Get the signature from the drive, compare it with the input
|
|
// parameter and if they are different, write new signature to
|
|
// disk.
|
|
//
|
|
if ( ( dwStatus = RdbpCompareAndWriteSignatureToDisk( hFile, dwSignature ) )
|
|
!= ERROR_SUCCESS )
|
|
{
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"[INIT] RdbFixupQuorumDiskSignature: Error %1!d! in attempting to write signature to %2!ws!\n",
|
|
dwStatus,
|
|
CsQuorumDriveLetter
|
|
);
|
|
bStatus = 0;
|
|
goto FnExit;
|
|
}
|
|
|
|
FnExit:
|
|
if ( hFile != INVALID_HANDLE_VALUE )
|
|
{
|
|
CloseHandle( hFile );
|
|
}
|
|
return ( bStatus );
|
|
}
|
|
|
|
/****
|
|
@func DWORD | RdbpOpenDiskDevice | Open and get a handle
|
|
to a physical disk device
|
|
|
|
@parm IN LPCWSTR | lpDriveLetter | The disk drive letter.
|
|
|
|
@parm OUT PHANDLE | pFileHandle | Pointer to the handle to the open
|
|
device.
|
|
|
|
@rdesc Returns ERROR_SUCCESS if successful. A Win32 error code on
|
|
failure.
|
|
|
|
@comm This function attempts to open a disk device and return a
|
|
handle to it. Different ways are used to open the device.
|
|
|
|
@xref <f RdbFixupQuorumDiskSignature>
|
|
****/
|
|
DWORD
|
|
RdbpOpenDiskDevice(
|
|
IN LPCWSTR lpDriveLetter,
|
|
OUT PHANDLE pFileHandle
|
|
)
|
|
{
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
DWORD accessMode;
|
|
DWORD shareMode;
|
|
DWORD dwStatus;
|
|
BOOL bFailed = FALSE;
|
|
WCHAR deviceNameString[128];
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 10/30/98
|
|
//
|
|
// Note it is important to access the device with 0 access mode
|
|
// so that the file open code won't do extra I/O to the device.
|
|
//
|
|
shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
|
accessMode = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
lstrcpyW( deviceNameString, L"\\\\.\\" );
|
|
lstrcatW( deviceNameString, lpDriveLetter );
|
|
|
|
hFile = CreateFileW( deviceNameString,
|
|
accessMode,
|
|
shareMode,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL );
|
|
|
|
if ( hFile == INVALID_HANDLE_VALUE )
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto FnExit;
|
|
}
|
|
|
|
dwStatus = ERROR_SUCCESS;
|
|
*pFileHandle = hFile;
|
|
|
|
FnExit:
|
|
return( dwStatus );
|
|
}
|
|
|
|
/****
|
|
@func DWORD | RdbpCompareAndWriteSignatureToDisk | Compare the
|
|
signature on disk with the input parameter and if they
|
|
are not the same, write the input parameter as a new signature.
|
|
|
|
@parm IN HANDLE | hFile | Handle to the disk device.
|
|
|
|
@parm IN DWORD | dwSignature | Signature to be compared with
|
|
exisiting disk signature.
|
|
|
|
@rdesc Returns ERROR_SUCCESS if successful. A Win32 error code on
|
|
failure.
|
|
|
|
@comm This function attempts to first get the drive layout, read the
|
|
signature information, and then if necessary write back a
|
|
new signature to the drive. [This code is stolen from Rod's
|
|
clusdisk\test\disktest.c and then adapted to suit our needs.]
|
|
|
|
@xref <f RdbFixupQuorumDiskSignature>
|
|
****/
|
|
DWORD
|
|
RdbpCompareAndWriteSignatureToDisk(
|
|
IN HANDLE hFile,
|
|
IN DWORD dwSignature
|
|
)
|
|
{
|
|
DWORD dwStatus;
|
|
DWORD dwBytesReturned;
|
|
DWORD dwDriveLayoutSize;
|
|
PDRIVE_LAYOUT_INFORMATION pDriveLayout = NULL;
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 10/30/98
|
|
//
|
|
if ( !ClRtlGetDriveLayoutTable( hFile, &pDriveLayout, &dwBytesReturned )) {
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"[INIT] RdbpCompareAndWriteSignatureToDisk: Error %1!d! in getting "
|
|
"drive layout from %2!ws!\n",
|
|
dwStatus,
|
|
CsQuorumDriveLetter
|
|
);
|
|
goto FnExit;
|
|
}
|
|
|
|
dwDriveLayoutSize = sizeof( DRIVE_LAYOUT_INFORMATION ) +
|
|
( sizeof( PARTITION_INFORMATION ) *
|
|
( pDriveLayout->PartitionCount - 1 ) );
|
|
|
|
if ( dwBytesReturned < dwDriveLayoutSize )
|
|
{
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"[INIT] RdbpCompareAndWriteSignatureToDisk: Error reading driveLayout information. Expected %1!u! bytes, got %2!u! bytes.\n",
|
|
dwDriveLayoutSize,
|
|
dwBytesReturned
|
|
);
|
|
dwStatus = ERROR_INSUFFICIENT_BUFFER;
|
|
goto FnExit;
|
|
}
|
|
|
|
if ( pDriveLayout->Signature == dwSignature )
|
|
{
|
|
dwStatus = ERROR_SUCCESS;
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbpCompareAndWriteSignatureToDisk: Disk %1!ws! signature is same as in registry. No fixup needed\n",
|
|
CsQuorumDriveLetter
|
|
);
|
|
goto FnExit;
|
|
}
|
|
//
|
|
// Change just the signature field and send an ioctl down
|
|
//
|
|
pDriveLayout->Signature = dwSignature;
|
|
|
|
if ( !DeviceIoControl( hFile,
|
|
IOCTL_DISK_SET_DRIVE_LAYOUT,
|
|
pDriveLayout,
|
|
dwDriveLayoutSize,
|
|
NULL,
|
|
0,
|
|
&dwBytesReturned,
|
|
FALSE ) )
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"[INIT] RdbpCompareAndWriteSignatureToDisk: Error %1!d! in setting drive layout to %2!ws!\n",
|
|
dwStatus,
|
|
CsQuorumDriveLetter
|
|
);
|
|
goto FnExit;
|
|
}
|
|
|
|
dwStatus = ERROR_SUCCESS;
|
|
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbpCompareAndWriteSignatureToDisk: Quorum disk signature fixed successfully\n"
|
|
);
|
|
|
|
FnExit:
|
|
if ( pDriveLayout != NULL ) {
|
|
LocalFree( pDriveLayout );
|
|
}
|
|
|
|
return( dwStatus );
|
|
}
|
|
|
|
#if 0
|
|
/****
|
|
@func DWORD | RdbStartSvcOnNodes | Start the cluster service on
|
|
the nodes in which you stopped the service.
|
|
|
|
@parm IN LPCWSTR | lpszServiceName | Name of the service to start.
|
|
|
|
@rdesc Returns a Win32 error code on failure. ERROR_SUCCESS on success.
|
|
|
|
@comm This function attempts to start the service on the nodes on
|
|
which it stopped the service for a restoration operation.
|
|
|
|
@xref <f RdbStopSvcOnNodes>
|
|
****/
|
|
DWORD
|
|
RdbStartSvcOnNodes(
|
|
IN LPCWSTR lpszServiceName
|
|
)
|
|
{
|
|
SC_HANDLE hService;
|
|
SC_HANDLE hSCManager;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
SERVICE_STATUS serviceStatus;
|
|
WCHAR szNodeName[CS_MAX_NODE_NAME_LENGTH + 1];
|
|
DWORD i;
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 11/4/98
|
|
//
|
|
// Walk through the list of nodes
|
|
//
|
|
for ( i=0; i<dwRdbpNodeCount; i++ )
|
|
{
|
|
lstrcpyW( szNodeName, szRdbpNodeNameList + i *
|
|
( CS_MAX_NODE_NAME_LENGTH + 1 ) );
|
|
|
|
//
|
|
// Open a handle to the service control manager
|
|
//
|
|
hSCManager = OpenSCManager( szNodeName,
|
|
NULL,
|
|
SC_MANAGER_ALL_ACCESS );
|
|
if ( hSCManager == NULL )
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbStartSvcOnNodes: Unable to open SC manager on node %1!ws!, Error = %2!d!\n",
|
|
szNodeName,
|
|
dwStatus);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Open a handle to the service
|
|
//
|
|
hService = OpenService( hSCManager,
|
|
lpszServiceName,
|
|
SERVICE_ALL_ACCESS );
|
|
|
|
CloseServiceHandle( hSCManager );
|
|
|
|
if ( hService == NULL )
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbStartSvcOnNodes: Unable to open handle to %1!ws! service on node %2!ws!, Error = %3!d!\n",
|
|
lpszServiceName,
|
|
szNodeName,
|
|
dwStatus);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check whether the service is already started.
|
|
//
|
|
if ( QueryServiceStatus( hService,
|
|
&serviceStatus ) )
|
|
{
|
|
if ( ( serviceStatus.dwCurrentState == SERVICE_RUNNING ) ||
|
|
( serviceStatus.dwCurrentState == SERVICE_START_PENDING ) )
|
|
{
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbStartSvcOnNodes: %1!ws! on node %2!ws! already started\n",
|
|
lpszServiceName,
|
|
szNodeName);
|
|
CloseServiceHandle( hService );
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, start the cluster service
|
|
//
|
|
if ( !StartService( hService,
|
|
0,
|
|
NULL ) )
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"[INIT] RdbStartSvcOnNodes: Unable to start cluster service on %1!ws!\n",
|
|
szNodeName
|
|
);
|
|
} else
|
|
{
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"[INIT] RdbStartSvcOnNodes: Cluster service started on %1!ws!\n",
|
|
szNodeName
|
|
);
|
|
}
|
|
//
|
|
// And, close the current handle
|
|
//
|
|
CloseServiceHandle( hService );
|
|
} // for
|
|
|
|
//
|
|
// Now free the memory
|
|
//
|
|
LocalFree( szRdbpNodeNameList );
|
|
|
|
return( dwStatus );
|
|
}
|
|
#endif
|
|
|
|
/****
|
|
@func DWORD | RdbInitialize | This function performs the
|
|
initialization steps necessary for the restore database
|
|
manager. Specifically, copy the most recent checkpoint
|
|
file from the backup path to the cluster directory overwriting
|
|
the CLUSDB there.
|
|
|
|
@rdesc Returns a Win32 error code if the operation is
|
|
unsuccessful. ERROR_SUCCESS on success.
|
|
|
|
@xref <f DmInitialize>
|
|
****/
|
|
DWORD
|
|
RdbInitialize(
|
|
VOID
|
|
)
|
|
{
|
|
HANDLE hFindFile = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATAW FindData;
|
|
DWORD dwStatus;
|
|
WCHAR szDestFileName[MAX_PATH];
|
|
LPWSTR szSourceFileName = NULL;
|
|
LPWSTR szSourcePathName = NULL;
|
|
DWORD dwLen;
|
|
WIN32_FILE_ATTRIBUTE_DATA FileAttributes;
|
|
LARGE_INTEGER liFileCreationTime;
|
|
LARGE_INTEGER liMaxFileCreationTime;
|
|
WCHAR szCheckpointFileName[MAX_PATH];
|
|
WCHAR szClusterDir[MAX_PATH];
|
|
LPCWSTR lpszPathName = CsDatabaseRestorePath;
|
|
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 12/4/99
|
|
//
|
|
|
|
//
|
|
// If there is no cluster database restore in progress, don't do anything.
|
|
//
|
|
if( CsDatabaseRestore == FALSE )
|
|
{
|
|
return( ERROR_SUCCESS );
|
|
}
|
|
|
|
ClRtlLogPrint(LOG_NOISE, "[INIT] RdbInitialize: Entry...\n");
|
|
|
|
dwLen = lstrlenW ( lpszPathName );
|
|
//
|
|
// It is safer to use dynamic memory allocation for user-supplied
|
|
// path since we don't want to put restrictions on the user
|
|
// on the length of the path that can be supplied. However, as
|
|
// far as our own destination path is concerned, it is system-dependent
|
|
// and static memory allocation for that would suffice.
|
|
//
|
|
szSourcePathName = (LPWSTR) LocalAlloc ( LMEM_FIXED,
|
|
( dwLen + 25 ) *
|
|
sizeof ( WCHAR ) );
|
|
|
|
if ( szSourcePathName == NULL )
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbInitialize: Error %1!d! in allocating memory for %2!ws!\n",
|
|
dwStatus,
|
|
lpszPathName);
|
|
goto FnExit;
|
|
}
|
|
|
|
lstrcpyW ( szSourcePathName, lpszPathName );
|
|
|
|
//
|
|
// If the client-supplied path is not already terminated with '\',
|
|
// then add it.
|
|
//
|
|
if ( szSourcePathName [dwLen-1] != L'\\' )
|
|
{
|
|
szSourcePathName [dwLen++] = L'\\';
|
|
szSourcePathName [dwLen] = L'\0';
|
|
}
|
|
|
|
lstrcatW ( szSourcePathName, L"CLUSBACKUP.DAT" );
|
|
|
|
//
|
|
// Try to find the CLUSBACKUP.DAT file in the directory
|
|
//
|
|
hFindFile = FindFirstFileW( szSourcePathName, &FindData );
|
|
//
|
|
// Reuse the source path name variable
|
|
//
|
|
szSourcePathName[dwLen] = L'\0';
|
|
if ( hFindFile == INVALID_HANDLE_VALUE )
|
|
{
|
|
dwStatus = GetLastError();
|
|
if ( dwStatus != ERROR_FILE_NOT_FOUND )
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbInitialize: Path %1!ws! unavailable, Error = %2!d!\n",
|
|
szSourcePathName,
|
|
dwStatus);
|
|
} else
|
|
{
|
|
dwStatus = ERROR_DATABASE_BACKUP_CORRUPT;
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbInitialize: Backup procedure from %1!ws! not fully"
|
|
" successful, can't restore checkpoint to CLUSDB, Error = %2!d! !!!\n",
|
|
szSourcePathName,
|
|
dwStatus);
|
|
}
|
|
goto FnExit;
|
|
}
|
|
FindClose ( hFindFile );
|
|
|
|
lstrcatW( szSourcePathName, L"chk*.tmp" );
|
|
|
|
//
|
|
// Try to find the first chk*.tmp file in the directory
|
|
//
|
|
hFindFile = FindFirstFileW( szSourcePathName, &FindData );
|
|
//
|
|
// Reuse the source path name variable
|
|
//
|
|
szSourcePathName[dwLen] = L'\0';
|
|
if ( hFindFile == INVALID_HANDLE_VALUE )
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbInitialize: Error %2!d! in trying"
|
|
"to find chk*.tmp file in path %1!ws!\r\n",
|
|
szSourcePathName,
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
|
|
szSourceFileName = (LPWSTR) LocalAlloc ( LMEM_FIXED,
|
|
( lstrlenW ( szSourcePathName ) + MAX_PATH ) *
|
|
sizeof ( WCHAR ) );
|
|
|
|
if ( szSourceFileName == NULL )
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbInitialize: Error %1!d! in allocating memory for source file name\n",
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
|
|
dwStatus = ERROR_SUCCESS;
|
|
liMaxFileCreationTime.QuadPart = 0;
|
|
|
|
//
|
|
// Now, find the most recent chk*.tmp file from the source path
|
|
//
|
|
while ( dwStatus == ERROR_SUCCESS )
|
|
{
|
|
if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
|
|
{
|
|
goto skip;
|
|
}
|
|
|
|
lstrcpyW( szSourceFileName, szSourcePathName );
|
|
lstrcatW( szSourceFileName, FindData.cFileName );
|
|
if ( !GetFileAttributesExW( szSourceFileName,
|
|
GetFileExInfoStandard,
|
|
&FileAttributes ) )
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_UNUSUAL, "[INIT] RdbInitialize: Error %1!d! in getting file"
|
|
" attributes for %2!ws!\n",
|
|
dwStatus,
|
|
szSourceFileName);
|
|
goto FnExit;
|
|
}
|
|
|
|
liFileCreationTime.HighPart = FileAttributes.ftCreationTime.dwHighDateTime;
|
|
liFileCreationTime.LowPart = FileAttributes.ftCreationTime.dwLowDateTime;
|
|
if ( liFileCreationTime.QuadPart > liMaxFileCreationTime.QuadPart )
|
|
{
|
|
liMaxFileCreationTime.QuadPart = liFileCreationTime.QuadPart;
|
|
lstrcpyW( szCheckpointFileName, FindData.cFileName );
|
|
}
|
|
skip:
|
|
if ( FindNextFileW( hFindFile, &FindData ) )
|
|
{
|
|
dwStatus = ERROR_SUCCESS;
|
|
} else
|
|
{
|
|
dwStatus = GetLastError();
|
|
}
|
|
}
|
|
|
|
if ( dwStatus == ERROR_NO_MORE_FILES )
|
|
{
|
|
dwStatus = ERROR_SUCCESS;
|
|
} else
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbInitialize: FindNextFile failed, error=%1!d!\n",
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Get the directory where the cluster is installed
|
|
//
|
|
if ( ( dwStatus = ClRtlGetClusterDirectory( szClusterDir, MAX_PATH ) )
|
|
!= ERROR_SUCCESS )
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbInitialize: Error %1!d! in getting cluster dir !!!\n",
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
|
|
lstrcpyW( szSourceFileName, szSourcePathName );
|
|
lstrcatW( szSourceFileName, szCheckpointFileName );
|
|
|
|
lstrcpyW( szDestFileName, szClusterDir );
|
|
dwLen = lstrlenW( szDestFileName );
|
|
if ( szDestFileName[dwLen-1] != L'\\' )
|
|
{
|
|
szDestFileName[dwLen++] = L'\\';
|
|
szDestFileName[dwLen] = L'\0';
|
|
}
|
|
|
|
#ifdef OLD_WAY
|
|
lstrcatW ( szDestFileName, L"CLUSDB" );
|
|
#else // OLD_WAY
|
|
lstrcatW ( szDestFileName, CLUSTER_DATABASE_NAME );
|
|
#endif // OLD_WAY
|
|
|
|
//
|
|
// Set the destination file attribute to normal. Continue even
|
|
// if you fail in this step because you will fail in the
|
|
// copy if this error is fatal.
|
|
//
|
|
SetFileAttributesW( szDestFileName, FILE_ATTRIBUTE_NORMAL );
|
|
|
|
//
|
|
// Now try to copy the checkpoint file to CLUSDB
|
|
//
|
|
dwStatus = CopyFileW( szSourceFileName, szDestFileName, FALSE );
|
|
if ( !dwStatus )
|
|
{
|
|
//
|
|
// You failed in copying. Check whether you encountered a
|
|
// sharing violation. If so, try unloading the cluster hive and
|
|
// then retry.
|
|
//
|
|
dwStatus = GetLastError();
|
|
if ( dwStatus == ERROR_SHARING_VIOLATION )
|
|
{
|
|
dwStatus = RdbpUnloadClusterHive( );
|
|
if ( dwStatus == ERROR_SUCCESS )
|
|
{
|
|
SetFileAttributesW( szDestFileName, FILE_ATTRIBUTE_NORMAL );
|
|
dwStatus = CopyFileW( szSourceFileName, szDestFileName, FALSE );
|
|
if ( !dwStatus )
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbInitialize: Unable to copy file %1!ws! "
|
|
"to %2!ws! for a second time, Error = %3!d!\n",
|
|
szSourceFileName,
|
|
szDestFileName,
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
} else
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbInitialize: Unable to unload cluster hive, Error = %1!d!\n",
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
} else
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbInitialize: Unable to copy file %1!ws! "
|
|
"to %2!ws! for the first time, Error = %3!d!\n",
|
|
szSourceFileName,
|
|
szDestFileName,
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the destination file attribute to normal.
|
|
//
|
|
if ( !SetFileAttributesW( szDestFileName, FILE_ATTRIBUTE_NORMAL ) )
|
|
{
|
|
dwStatus = GetLastError();
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbInitialize: Unable to change the %1!ws! "
|
|
"attributes to normal, Error = %2!d!\n",
|
|
szDestFileName,
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
|
|
dwStatus = ERROR_SUCCESS;
|
|
FnExit:
|
|
if ( hFindFile != INVALID_HANDLE_VALUE )
|
|
{
|
|
FindClose( hFindFile );
|
|
}
|
|
|
|
LocalFree( szSourcePathName );
|
|
LocalFree( szSourceFileName );
|
|
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbInitialize: Exit with Status = %1!d!...\n",
|
|
dwStatus);
|
|
|
|
return( dwStatus );
|
|
}
|
|
|
|
/****
|
|
@func DWORD | RdbpUnloadClusterHive | Unload the cluster hive
|
|
|
|
@rdesc Returns a Win32 error code if the operation is
|
|
unsuccessful. ERROR_SUCCESS on success.
|
|
|
|
@xref <f RdbInitialize>
|
|
****/
|
|
DWORD
|
|
RdbpUnloadClusterHive(
|
|
VOID
|
|
)
|
|
{
|
|
BOOLEAN bWasEnabled;
|
|
DWORD dwStatus;
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 12/4/99
|
|
//
|
|
dwStatus = ClRtlEnableThreadPrivilege( SE_RESTORE_PRIVILEGE,
|
|
&bWasEnabled );
|
|
|
|
if ( dwStatus != ERROR_SUCCESS )
|
|
{
|
|
if ( dwStatus == STATUS_PRIVILEGE_NOT_HELD )
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbpUnloadClusterHive: Restore privilege not held by client\n");
|
|
} else
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbpUnloadClusterHive: Attempt to enable restore "
|
|
"privilege failed, Error = %1!d!\n",
|
|
dwStatus);
|
|
}
|
|
goto FnExit;
|
|
}
|
|
|
|
dwStatus = RegUnLoadKeyW( HKEY_LOCAL_MACHINE,
|
|
CLUSREG_KEYNAME_CLUSTER );
|
|
|
|
ClRtlRestoreThreadPrivilege( SE_RESTORE_PRIVILEGE,
|
|
bWasEnabled );
|
|
FnExit:
|
|
return( dwStatus );
|
|
}
|
|
|
|
/****
|
|
@func DWORD | RdbpDeleteRestoreDbParams | Clean up the restore parameters stored
|
|
under HKLM\System\CCC\Services\Clussvc\Parameters. The RestoreClusterDatabase
|
|
API will also attempt to do this.
|
|
|
|
@comm This function attempts clean the registry parameters for the restore database
|
|
operation.
|
|
|
|
@rdesc Returns a Win32 error code if the opening of the params key is unsuccessful.
|
|
ERROR_SUCCESS on success.
|
|
|
|
@xref <f RdbGetRestoreDbParams>
|
|
****/
|
|
DWORD
|
|
RdbpDeleteRestoreDbParams(
|
|
VOID
|
|
)
|
|
{
|
|
HKEY hClusSvcKey = NULL;
|
|
DWORD dwStatus;
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 08/28/2000
|
|
//
|
|
if( CsDatabaseRestore == FALSE )
|
|
{
|
|
return( ERROR_SUCCESS );
|
|
}
|
|
|
|
ClRtlLogPrint(LOG_NOISE, "[INIT] RdbDeleteRestoreDbParams: Entry...\n");
|
|
|
|
//
|
|
// Open key to SYSTEM\CurrentControlSet\Services\ClusSvc\Parameters
|
|
//
|
|
dwStatus = RegOpenKeyW( HKEY_LOCAL_MACHINE,
|
|
CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
|
|
&hClusSvcKey );
|
|
|
|
if( dwStatus != ERROR_SUCCESS )
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[INIT] RdbDeleteRestoreDbParams: Unable to open clussvc params key, error=%1!u!...\n",
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Try to delete the values you set. You may fail in these steps, because all these values need
|
|
// not be present in the registry.
|
|
//
|
|
dwStatus = RegDeleteValueW( hClusSvcKey,
|
|
CLUSREG_NAME_SVC_PARAM_RESTORE_DB );
|
|
|
|
if ( ( dwStatus != ERROR_SUCCESS ) && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
|
|
{
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbDeleteRestoreDbParams: Unable to delete %2!ws! param value, error=%1!u!...\n",
|
|
dwStatus,
|
|
CLUSREG_NAME_SVC_PARAM_RESTORE_DB);
|
|
}
|
|
|
|
dwStatus = RegDeleteValueW( hClusSvcKey,
|
|
CLUSREG_NAME_SVC_PARAM_FORCE_RESTORE_DB );
|
|
|
|
if ( ( dwStatus != ERROR_SUCCESS ) && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
|
|
{
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbDeleteRestoreDbParams: Unable to delete %2!ws! param value, error=%1!u!...\n",
|
|
dwStatus,
|
|
CLUSREG_NAME_SVC_PARAM_FORCE_RESTORE_DB);
|
|
}
|
|
|
|
dwStatus = RegDeleteValueW( hClusSvcKey,
|
|
CLUSREG_NAME_SVC_PARAM_QUORUM_DRIVE_LETTER );
|
|
|
|
if ( ( dwStatus != ERROR_SUCCESS ) && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
|
|
{
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[INIT] RdbDeleteRestoreDbParams: Unable to delete %2!ws! param value, error=%1!u!...\n",
|
|
dwStatus,
|
|
CLUSREG_NAME_SVC_PARAM_QUORUM_DRIVE_LETTER);
|
|
}
|
|
|
|
dwStatus = ERROR_SUCCESS;
|
|
|
|
FnExit:
|
|
if ( hClusSvcKey != NULL )
|
|
{
|
|
RegCloseKey( hClusSvcKey );
|
|
}
|
|
|
|
ClRtlLogPrint(LOG_NOISE, "[INIT] RdbDeleteRestoreDbParams: Exit with status=%1!u!...\n",
|
|
dwStatus);
|
|
|
|
return( dwStatus );
|
|
}
|