|
|
/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
gencmd.c
Abstract:
Resource DLL for Generic Command line services. This is a modified version of generic app. Online and offline events each create a command window, execute a command, then delete the command window.
Author:
Rod Gamache (rodga) 8-Jan-1996 Robs - modified to make gencmd version
Revision History:
--*/
#define UNICODE 1
#include "windows.h"
#include "stdio.h"
#include "clusapi.h"
#include "resapi.h"
#define MAX_APPS 200
#define GENCMD_PRINT printf
typedef struct _MY_PROCESS_INFORMATION { PROCESS_INFORMATION; ULONG Index; RESOURCE_HANDLE ResourceHandle; PTSTR AppName; PTSTR OnCommandLine; PTSTR OffCommandLine; PTSTR CurDir; } MY_PROCESS_INFORMATION, *PMY_PROCESS_INFORMATION;
//
// Global Data
//
// Lock to protect the ProcessInfo table
CRITICAL_SECTION ProcessLock;
// The list of handles for active apps
PMY_PROCESS_INFORMATION ProcessInfo[MAX_APPS];
// Event Logging routine
PLOG_EVENT_ROUTINE GenCmdLogEvent = NULL;
extern CLRES_FUNCTION_TABLE GenCmdFunctionTable;
//
// Forward routines
//
LPWSTR GetParameter( IN HKEY ClusterKey, IN LPCWSTR ValueName );
BOOLEAN GenCmdInit( VOID ) { InitializeCriticalSection( &ProcessLock ); return(TRUE); }
BOOLEAN WINAPI GenCmdDllEntryPoint( IN HINSTANCE DllHandle, IN DWORD Reason, IN LPVOID Reserved ) {
switch( Reason ) {
case DLL_PROCESS_ATTACH: if ( !GenCmdInit() ) { return(FALSE); }
break;
case DLL_PROCESS_DETACH: break;
default: break; }
return(TRUE);
} // GenCmd DllEntryPoint
DWORD WINAPI Startup( IN LPCWSTR ResourceType, IN DWORD MinVersionSupported, IN DWORD MaxVersionSupported, IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus, IN PLOG_EVENT_ROUTINE LogEvent, OUT PCLRES_FUNCTION_TABLE *FunctionTable )
/*++
Routine Description:
Startup a particular resource type. This means verifying the version requested, and returning the function table for this resource type.
Arguments:
ResourceType - Supplies the type of resource.
MinVersionSupported - The minimum version number supported by the cluster service on this system.
MaxVersionSupported - The maximum version number supported by the cluster service on this system.
FunctionTable - Returns the Function Table for this resource type.
Return Value:
ERROR_SUCCESS if successful.
A Win32 error code on failure.
--*/
{ if ( _wcsicmp( ResourceType, L"Generic Command" ) != 0 ) { return(ERROR_UNKNOWN_REVISION); }
if ( (MinVersionSupported <= CLRES_VERSION_V1_00) && (MaxVersionSupported >= CLRES_VERSION_V1_00) ) { *FunctionTable = &GenCmdFunctionTable; return(ERROR_SUCCESS); } GenCmdLogEvent = LogEvent;
return(ERROR_REVISION_MISMATCH);
} // Startup
RESID WINAPI GenCmdOpen( IN LPCWSTR ResourceName, IN HKEY ResourceKey, IN RESOURCE_HANDLE ResourceHandle )
/*++
Routine Description:
Open routine for generic service resource.
Arguments:
ResourceName - supplies the resource name
ResourceKey - supplies a handle to the resource's cluster registry key
ResourceHandle - the resource handle to be supplied with SetResourceStatus is called.
Return Value:
RESID of created resource Zero on failure
--*/
{ ULONG index; RESID appResid = 0; DWORD errorCode; HKEY parametersKey = NULL; PMY_PROCESS_INFORMATION processInfo = NULL; DWORD paramNameSize = 0; DWORD paramNameMaxSize = 0;
// Create Process parameters
LPWSTR appName; LPWSTR OncommandLine; LPWSTR OffcommandLine; LPWSTR curDir;
//
// Get registry parameters for this resource.
//
(GenCmdLogEvent)( ResourceHandle, LOG_INFORMATION, L"Creating generic command resource.\n" );
errorCode = ClusterRegOpenKey( ResourceKey, L"Parameters", KEY_READ, ¶metersKey );
if ( errorCode != NO_ERROR ) { (GenCmdLogEvent)( ResourceHandle, LOG_ERROR, L"Unable to open parameters key. Error: %1!u!.\n", errorCode); goto error_exit; }
//
// Read our parameters.
//
// Get the ImageName parameter
appName = GetParameter(parametersKey, L"ImageName");
if ( appName == NULL ) { (GenCmdLogEvent)( ResourceHandle, LOG_ERROR, L"Unable to read ImageName parameter. Error: %1!u!.\n", GetLastError() ); goto error_exit; }
// Get the CommandLine parameter
OncommandLine = GetParameter(parametersKey, L"OnCommandLine");
if ( OncommandLine == NULL ) { (GenCmdLogEvent)( ResourceHandle, LOG_INFORMATION, L"Resource create request but no Online command supplied.\n"); OncommandLine = L""; }
OffcommandLine = GetParameter(parametersKey, L"OffCommandLine");
if ( OncommandLine == NULL ) { (GenCmdLogEvent)( ResourceHandle, LOG_INFORMATION, L"Resource create request but no Offline command supplied.\n"); OncommandLine = L"";
}
// Get the CurrentDirectory parameter
curDir = GetParameter(parametersKey, L"CurrentDirectory");
if ( (curDir == NULL) || (wcslen(curDir) == 0) ) { curDir = NULL; }
//
// Find a free index in the process info table for this new app.
//
EnterCriticalSection( &ProcessLock );
for ( index = 1; index <= MAX_APPS; index++ ) { if ( ProcessInfo[index-1] == NULL ) { break; } }
// Check if there was room in the process table.
if ( index > MAX_APPS ) { LeaveCriticalSection( &ProcessLock ); (GenCmdLogEvent)( ResourceHandle, LOG_ERROR, L"Too many applications to watch.\n"); goto error_exit; }
processInfo = LocalAlloc( LMEM_FIXED, sizeof(MY_PROCESS_INFORMATION) );
if ( processInfo == NULL ) { LeaveCriticalSection( &ProcessLock ); (GenCmdLogEvent)( ResourceHandle, LOG_ERROR, L"Failed to allocate a process info structure.\n"); goto error_exit; }
ProcessInfo[index-1] = processInfo;
LeaveCriticalSection( &ProcessLock );
ZeroMemory( processInfo, sizeof(MY_PROCESS_INFORMATION) );
processInfo->Index = index; processInfo->AppName = appName; processInfo->OnCommandLine = OncommandLine; processInfo->OffCommandLine = OffcommandLine; processInfo->CurDir = curDir; processInfo->ResourceHandle = ResourceHandle;
appResid = (RESID)index;
error_exit:
if ( parametersKey != NULL ) { ClusterRegCloseKey( parametersKey ); }
if ( (appResid == 0) && (processInfo != NULL) ) { ProcessInfo[processInfo->Index] = NULL; LocalFree( processInfo ); }
return(appResid);
} // GenCmdOpen
DWORD WINAPI GenCmdOnline( IN RESID Resource, IN OUT PHANDLE EventHandle )
/*++
Routine Description:
Online routine for Generic Application resource.
Arguments:
Resource - supplies resource id to be brought online
EventHandle - supplies a pointer to a handle to signal on error.
Return Value:
ERROR_SUCCESS if successful. ERROR_RESOURCE_NOT_FOUND if RESID is not valid. ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to acquire 'ownership'. Win32 error code if other failure.
--*/
{ PMY_PROCESS_INFORMATION processInfo; DWORD status = ERROR_SUCCESS; DWORD index; SECURITY_ATTRIBUTES process = {0}; SECURITY_ATTRIBUTES thread = {0}; DWORD create = 0; STARTUPINFO startupInfo = {0};
startupInfo.cb = sizeof(STARTUPINFO);
index = PtrToUlong(Resource) - 1; processInfo = ProcessInfo[index];
if ( processInfo == NULL ) { GENCMD_PRINT("GenCmd: Online request for a nonexistent resource id %u.\n", PtrToUlong(Resource)); return(ERROR_RESOURCE_NOT_FOUND); }
if ( processInfo->Index != PtrToUlong(Resource) ) { (GenCmdLogEvent)( processInfo->ResourceHandle, LOG_ERROR, L"Online process index sanity checked failed! Index = %1!u!.\n", PtrToUlong(Resource)); return(ERROR_RESOURCE_NOT_FOUND); }
(GenCmdLogEvent)( processInfo->ResourceHandle, LOG_ERROR, L"About to create process, cmd = %1!ws!.\n", processInfo->OnCommandLine);
if ( !CreateProcess( processInfo->AppName, processInfo->OnCommandLine, &process, // Process security attributes
&thread, // Thread security attributes
FALSE, // Don't inherit handles from us
create, // Creation Flags
NULL, // No environmet block
processInfo->CurDir, // Current Directory
&startupInfo, // Startup info
(PPROCESS_INFORMATION)processInfo ) ) {
(GenCmdLogEvent)( processInfo->ResourceHandle, LOG_ERROR, L"Failed to create process. Error: %1!u!.\n", status = GetLastError() ); return(status); }
return(status);
} // GenCmdOnline
VOID WINAPI GenCmdTerminate( IN RESID Resource )
/*++
Routine Description:
Terminate routine for Generic Application resource.
Arguments:
Resource - supplies resource id to be terminated
Return Value:
None.
--*/
{
PMY_PROCESS_INFORMATION processInfo; DWORD index; SECURITY_ATTRIBUTES process = {0}; SECURITY_ATTRIBUTES thread = {0}; DWORD create = 0; STARTUPINFO startupInfo = {0}; DWORD errorCode;
index = PtrToUlong(Resource) - 1; processInfo = ProcessInfo[index];
if ( processInfo == NULL ) { GENCMD_PRINT("GenCmd: Offline request for a nonexistent resource id %u.\n", PtrToUlong(Resource)); return; }
if ( processInfo->Index != PtrToUlong(Resource) ) { (GenCmdLogEvent)( processInfo->ResourceHandle, LOG_ERROR, L"Offline process index sanity checked failed! Index = %1!u!.\n", PtrToUlong(Resource)); return; }
if ( !CreateProcess( processInfo->AppName, processInfo->OffCommandLine, &process, // Process security attributes
&thread, // Thread security attributes
FALSE, // Don't inherit handles from us
create, // Creation Flags
NULL, // No environmet block
processInfo->CurDir, // Current Directory
&startupInfo, // Startup info
(PPROCESS_INFORMATION)processInfo ) ) {
(GenCmdLogEvent)( processInfo->ResourceHandle, LOG_ERROR, L"Offline failed to create process. Error: %1!u!.\n", GetLastError() ); }
} // GenCmdTerminate
DWORD WINAPI GenCmdOffline( IN RESID Resource )
/*++
Routine Description:
Offline routine for Generic Command resource.
Arguments:
Resource - supplies the resource to be taken offline
Return Value:
ERROR_SUCCESS - always successful.
--*/
{ GenCmdTerminate( Resource );
return(ERROR_SUCCESS);
} // GenCmdOffline
BOOL WINAPI GenCmdIsAlive( IN RESID Resource )
/*++
Routine Description:
IsAlive routine for Generice service resource.
Arguments:
Resource - supplies the resource id to be polled.
Return Value:
TRUE - Always, we just pretend everything is fine
--*/
{ return(TRUE);
} // GenCmdIsAlive
BOOL WINAPI GenCmdLooksAlive( IN RESID Resource )
/*++
Routine Description:
LooksAlive routine for Generic Applications resource.
Arguments:
Resource - supplies the resource id to be polled.
Return Value:
TRUE - Resource looks like it is alive and well
FALSE - Resource looks like it is toast.
--*/
{ PMY_PROCESS_INFORMATION processInfo; DWORD index;
index = PtrToUlong(Resource) - 1; processInfo = ProcessInfo[index];
if ( processInfo == NULL ) { GENCMD_PRINT("GenCmd: Offline request for a nonexistent resource id %u.\n", PtrToUlong(Resource)); return(FALSE); }
return(TRUE);
} // GenCmdLooksAlive
VOID WINAPI GenCmdClose( IN RESID Resource )
/*++
Routine Description:
Close routine for Generic Applications resource.
Arguments:
Resource - supplies resource id to be closed
Return Value:
None.
--*/
{ PMY_PROCESS_INFORMATION processInfo; DWORD errorCode; DWORD index;
index = PtrToUlong(Resource) - 1; processInfo = ProcessInfo[index];
if ( processInfo == NULL ) { GENCMD_PRINT("GenCmd: Close request for a nonexistent resource id %u\n", PtrToUlong(Resource)); return; }
if ( processInfo->Index != PtrToUlong(Resource) ) { (GenCmdLogEvent)( processInfo->ResourceHandle, LOG_ERROR, L"Close process index sanity check failed! Index = %1!u!.\n", PtrToUlong(Resource) ); return; }
(GenCmdLogEvent)( processInfo->ResourceHandle, LOG_INFORMATION, L"Close request for Process%1!d!.\n", PtrToUlong(Resource));
ProcessInfo[index] = NULL;
LocalFree( processInfo );
} // GenCmdClose
LPWSTR GetParameter( IN HKEY ClusterKey, IN LPCWSTR ValueName )
/*++
Routine Description:
Queries a REG_SZ parameter out of the registry and allocates the necessary storage for it.
Arguments:
ClusterKey - Supplies the cluster key where the parameter is stored
ValueName - Supplies the name of the value.
Return Value:
A pointer to a buffer containing the parameter if successful.
NULL if unsuccessful.
--*/
{ LPWSTR Value; DWORD ValueLength; DWORD ValueType; DWORD Status;
ValueLength = 0; Status = ClusterRegQueryValue(ClusterKey, ValueName, &ValueType, NULL, &ValueLength); if ( (Status != ERROR_SUCCESS) && (Status != ERROR_MORE_DATA) ) { SetLastError(Status); return(NULL); } if ( ValueType == REG_SZ ) { ValueLength += sizeof(UNICODE_NULL); } Value = LocalAlloc(LMEM_FIXED, ValueLength); if (Value == NULL) { return(NULL); } Status = ClusterRegQueryValue(ClusterKey, ValueName, &ValueType, (LPBYTE)Value, &ValueLength); if (Status != ERROR_SUCCESS) { LocalFree(Value); SetLastError(Status); Value = NULL; }
return(Value); } // GetParameter
//***********************************************************
//
// Define Function Table
//
//***********************************************************
CLRES_V1_FUNCTION_TABLE( GenCmdFunctionTable, CLRES_VERSION_V1_00, GenCmd, NULL, NULL, NULL, NULL );
|