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.
761 lines
16 KiB
761 lines
16 KiB
/*++
|
|
|
|
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 );
|
|
|