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.
2511 lines
73 KiB
2511 lines
73 KiB
/*++
|
|
|
|
Copyright (c) 1992-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
GenJob.c
|
|
|
|
Abstract:
|
|
|
|
Resource DLL for Generic Job Objects (based on genapp)
|
|
|
|
Author:
|
|
|
|
Charlie Wickham (charlwi) 4-14-99
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define UNICODE 1
|
|
#include "clusres.h"
|
|
#include "clusrtl.h"
|
|
#include "jobmsg.h"
|
|
|
|
// move to clusres.h
|
|
#define LOG_MODULE_GENJOB 0x80F
|
|
|
|
#define LOG_CURRENT_MODULE LOG_MODULE_GENJOB
|
|
|
|
#define DBG_PRINT printf
|
|
|
|
// move to clusudef.h
|
|
#define CLUS_RESTYPE_NAME_GENJOB L"Generic Job Object"
|
|
#define CLUSREG_NAME_GENJOB_COMMAND_LINE L"CommandLine"
|
|
#define CLUSREG_NAME_GENJOB_CURRENT_DIRECTORY L"CurrentDirectory"
|
|
#define CLUSREG_NAME_GENJOB_INTERACT_WITH_DESKTOP L"InteractWithDesktop"
|
|
#define CLUSREG_NAME_GENJOB_USE_NETWORK_NAME L"UseNetworkName"
|
|
|
|
// delete these when moving to clusres
|
|
PSET_RESOURCE_STATUS_ROUTINE ClusResSetResourceStatus = NULL;
|
|
PLOG_EVENT_ROUTINE ClusResLogEvent = NULL;
|
|
|
|
//
|
|
// Private properties structure.
|
|
//
|
|
typedef struct _GENJOB_PROPS
|
|
{
|
|
PWSTR CommandLine; // first process in job
|
|
PWSTR CurrentDirectory; // directory to associated with process
|
|
DWORD InteractWithDesktop; // true sets desktop to "winsta0\default"
|
|
DWORD UseNetworkName; // true if associated netname should be replaced in environment
|
|
BOOL UseDefaults; // true if all job obj defaults are used
|
|
|
|
BOOL ProcsCanBreakaway; // true sets JOB_OBJECT_LIMIT_BREAKAWAY_OK
|
|
BOOL ProcsCanSilentlyBreakaway; // true sets JOB_OBJECT_LIMIT_SILENT_BREAKAWAY
|
|
BOOL SetActiveProcessLimit; // true sets JOB_OBJECT_LIMIT_ACTIVE_PROCESS
|
|
DWORD ActiveProcessLimit; // sets BasicLimitInformation.ActiveProcessLimit
|
|
BOOL SetAffinity; // true sets JOB_OBJECT_LIMIT_AFFINITY
|
|
DWORD Affinity; // sets BasicLimitInformation.Affinity
|
|
BOOL SetJobUserTimeLimit; // true sets JOB_OBJECT_LIMIT_JOB_TIME
|
|
DWORD PerJobUserTimeLimit; // sets BasicLimitInformation.PerJobUserTimeLimit
|
|
BOOL SetPriorityClass; // true sets JOB_OBJECT_LIMIT_PRIORITY_CLASS
|
|
DWORD PriorityClass; // sets BasicLimitInformation.PriorityClass
|
|
BOOL SetProcessUserTimeLimit; // true sets JOB_OBJECT_LIMIT_PROCESS_TIME
|
|
DWORD PerProcessUserTimeLimit; // sets BasicLimitInformation.PerProcessUserTimeLimit
|
|
BOOL SetSchedulingClass; // true sets JOB_OBJECT_LIMIT_SCHEDULING_CLASS
|
|
DWORD SchedulingClass; // sets BasicLimitInformation.SchedulingClass
|
|
BOOL SetWorkingSetSize; // true sets JOB_OBJECT_LIMIT_WORKINGSET
|
|
DWORD MaximumWorkingSetSize; // sets BasicLimitInformation.MaximumWorkingSetSize
|
|
DWORD MinimumWorkingSetSize; // sets BasicLimitInformation.MinimumWorkingSetSize
|
|
|
|
BOOL ManipulateDesktops; // false sets JOB_OBJECT_UILIMIT_DESKTOP
|
|
BOOL ChangeDisplaySettings; // false sets JOB_OBJECT_UILIMIT_DISPLAYSETTINGS
|
|
BOOL AllowSystemShutdown; // false sets JOB_OBJECT_UILIMIT_EXITWINDOWS
|
|
BOOL AccessGlobalAtoms; // false sets JOB_OBJECT_UILIMIT_GLOBALATOMS
|
|
BOOL AllowOtherProcessUSERHandles; // false sets JOB_OBJECT_UILIMIT_HANDLES
|
|
BOOL ReadFromClipboard; // false sets JOB_OBJECT_UILIMIT_READCLIPBOARD
|
|
BOOL ChangeSystemParameters; // false sets JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS
|
|
BOOL WriteToClipboard; // false sets JOB_OBJECT_UILIMIT_WRITECLIPBOARD
|
|
|
|
BOOL TerminateOnTimeLimit; // false sets JOB_OBJECT_POST_AT_END_OF_JOB
|
|
|
|
BOOL SetJobMemoryLimit; // true sets JOB_OBJECT_LIMIT_JOB_MEMORY in Basic.LimitFlags
|
|
DWORD JobMemoryLimit; // sets ExtendedLimits.JobMemoryLimit
|
|
BOOL SetProcessMemoryLimit; // true sets JOB_OBJECT_LIMIT_PROCESS_MEMORY
|
|
DWORD ProcessMemoryLimit; // sets ExtendedLimits.ProcessMemoryLimit
|
|
|
|
BOOL AllowLocalAdminTokens; // false sets JOB_OBJECT_SECURITY_NO_ADMIN
|
|
BOOL AllowUseOfRestrictedTokens; // false sets JOB_OBJECT_SECURITY_RESTRICTED_TOKEN
|
|
} GENJOB_PROPS, * PGENJOB_PROPS;
|
|
|
|
//
|
|
// top level per-resource instance structure
|
|
//
|
|
typedef struct _GENJOB_RESOURCE {
|
|
GENJOB_PROPS OperationalProps; // props associated with online resource
|
|
GENJOB_PROPS StoredProps; // props to be used next time resource is online
|
|
HRESOURCE hResource; // cluster handle to this resource
|
|
DWORD ProcessId; // PID of initial process
|
|
HKEY ResourceKey; // handle to this resource's key
|
|
HKEY ParametersKey; // handle to this resource's params key
|
|
HANDLE JobHandle; // backing job object handle
|
|
HANDLE OfflineEvent; // signalled when resource goes offline
|
|
RESOURCE_HANDLE ResourceHandle; // resmon pointer to its structure
|
|
CLUS_WORKER OnlineThread; // background online processing thread
|
|
BOOL Online; // true if online
|
|
} GENJOB_RESOURCE, *PGENJOB_RESOURCE;
|
|
|
|
//
|
|
// property definitions
|
|
//
|
|
#define PROP_NAME__COMMANDLINE CLUSREG_NAME_GENJOB_COMMAND_LINE
|
|
#define PROP_NAME__CURRENTDIRECTORY CLUSREG_NAME_GENJOB_CURRENT_DIRECTORY
|
|
#define PROP_NAME__INTERACTWITHDESKTOP CLUSREG_NAME_GENJOB_INTERACT_WITH_DESKTOP
|
|
#define PROP_NAME__USENETWORKNAME CLUSREG_NAME_GENJOB_USE_NETWORK_NAME
|
|
#define PROP_NAME__USEDEFAULTS L"UseDefaults"
|
|
|
|
#define PROP_NAME__PROCSCANBREAKAWAY L"ProcsCanBreakaway"
|
|
#define PROP_NAME__PROCSCANSILENTLYBREAKAWAY L"ProcsCanSilentlyBreakaway"
|
|
#define PROP_NAME__SETACTIVEPROCESSLIMIT L"SetActiveProcessLimit"
|
|
#define PROP_NAME__ACTIVEPROCESSLIMIT L"ActiveProcessLimit"
|
|
#define PROP_NAME__SETAFFINITY L"SetAffinity"
|
|
#define PROP_NAME__AFFINITY L"Affinity"
|
|
#define PROP_NAME__SETJOBUSERTIMELIMIT L"SetJobUserTimeLimit"
|
|
#define PROP_NAME__PERJOBUSERTIMELIMIT L"PerJobUserTimeLimit"
|
|
#define PROP_NAME__SETPRIORITYCLASS L"SetPriorityClass"
|
|
#define PROP_NAME__PRIORITYCLASS L"PriorityClass"
|
|
#define PROP_NAME__SETPROCESSUSERTIMELIMIT L"SetProcessUserTimeLimit"
|
|
#define PROP_NAME__PERPROCESSUSERTIMELIMIT L"PerProcessUserTimelimit"
|
|
#define PROP_NAME__SETSCHEDULINGCLASS L"SetSchedulingClass"
|
|
#define PROP_NAME__SCHEDULINGCLASS L"SchedulingClass"
|
|
#define PROP_NAME__SETWORKINGSETSIZE L"SetWorkingSetSize"
|
|
#define PROP_NAME__MAXIMUMWORKINGSETSIZE L"MaximumWorkingSetSize"
|
|
#define PROP_NAME__MINIMUMWORKINGSETSIZE L"MinimumWorkingSetSize"
|
|
|
|
#define PROP_NAME__MANIPULATEDESKTOPS L"ManipulateDesktops"
|
|
#define PROP_NAME__CHANGEDISPLAYSETTINGS L"ChangeDisplaySettings"
|
|
#define PROP_NAME__ALLOWSYSTEMSHUTDOWN L"Allowsystemshutdown"
|
|
#define PROP_NAME__ACCESSGLOBALATOMS L"AccessGlobalAtoms"
|
|
#define PROP_NAME__ALLOWOTHERPROCESSUSERHANDLES L"AllowOtherProcessUSERHandles"
|
|
#define PROP_NAME__READFROMCLIPBOARD L"ReadFromClipboard"
|
|
#define PROP_NAME__CHANGESYSTEMPARAMETERS L"ChangeSystemParameters"
|
|
#define PROP_NAME__WRITETOCLIPBOARD L"WriteToClipboard"
|
|
|
|
#define PROP_NAME__TERMINATEONTIMELIMIT L"TerminateOnTimeLimit"
|
|
|
|
#define PROP_NAME__SETJOBMEMORYLIMIT L"SetJobMemoryLimit"
|
|
#define PROP_NAME__JOBMEMORYLIMIT L"JobMemoryLimit"
|
|
#define PROP_NAME__SETPROCESSMEMORYLIMIT L"SetProcessMemoryLimit"
|
|
#define PROP_NAME__PROCESSMEMORYLIMIT L"ProcessMemoryLimit"
|
|
|
|
#define PROP_NAME__ALLOWLOCALADMINTOKENS L"AllowLocalAdminTokens"
|
|
#define PROP_NAME__ALLOWUSEOFRESTRICTEDTOKENS L"AllowUseOfRestrictedTokens"
|
|
|
|
//
|
|
// min, max, defaults for each non-string property
|
|
//
|
|
|
|
#define PROP_MIN__INTERACTWITHDESKTOP 0
|
|
#define PROP_MAX__INTERACTWITHDESKTOP 1
|
|
#define PROP_DEFAULT__INTERACTWITHDESKTOP 0
|
|
|
|
#define PROP_MIN__USENETWORKNAME 0
|
|
#define PROP_MAX__USENETWORKNAME 1
|
|
#define PROP_DEFAULT__USENETWORKNAME 0
|
|
|
|
#define PROP_MIN__USEDEFAULTS 0
|
|
#define PROP_MAX__USEDEFAULTS 1
|
|
#define PROP_DEFAULT__USEDEFAULTS 1
|
|
|
|
#define PROP_MIN__PROCSCANBREAKAWAY (0)
|
|
#define PROP_MAX__PROCSCANBREAKAWAY (1)
|
|
#define PROP_DEFAULT__PROCSCANBREAKAWAY (0)
|
|
|
|
#define PROP_MIN__PROCSCANSILENTLYBREAKAWAY (0)
|
|
#define PROP_MAX__PROCSCANSILENTLYBREAKAWAY (1)
|
|
#define PROP_DEFAULT__PROCSCANSILENTLYBREAKAWAY (0)
|
|
|
|
#define PROP_MIN__SETACTIVEPROCESSLIMIT (0)
|
|
#define PROP_MAX__SETACTIVEPROCESSLIMIT (1)
|
|
#define PROP_DEFAULT__SETACTIVEPROCESSLIMIT (0)
|
|
|
|
#define PROP_MIN__ACTIVEPROCESSLIMIT (1)
|
|
#define PROP_MAX__ACTIVEPROCESSLIMIT (4294967295)
|
|
#define PROP_DEFAULT__ACTIVEPROCESSLIMIT (1)
|
|
|
|
#define PROP_MIN__SETAFFINITY (0)
|
|
#define PROP_MAX__SETAFFINITY (1)
|
|
#define PROP_DEFAULT__SETAFFINITY (0)
|
|
|
|
#define PROP_MIN__AFFINITY (1)
|
|
#define PROP_MAX__AFFINITY (4294967295)
|
|
#define PROP_DEFAULT__AFFINITY (1)
|
|
|
|
#define PROP_MIN__SETJOBUSERTIMELIMIT (0)
|
|
#define PROP_MAX__SETJOBUSERTIMELIMIT (1)
|
|
#define PROP_DEFAULT__SETJOBUSERTIMELIMIT (0)
|
|
|
|
#define PROP_MIN__PERJOBUSERTIMELIMIT (1)
|
|
#define PROP_MAX__PERJOBUSERTIMELIMIT (4294967295)
|
|
#define PROP_DEFAULT__PERJOBUSERTIMELIMIT (1)
|
|
|
|
#define PROP_MIN__SETPRIORITYCLASS (0)
|
|
#define PROP_MAX__SETPRIORITYCLASS (1)
|
|
#define PROP_DEFAULT__SETPRIORITYCLASS (0)
|
|
|
|
#define PROP_MIN__PRIORITYCLASS (0)
|
|
#define PROP_MAX__PRIORITYCLASS (31)
|
|
#define PROP_DEFAULT__PRIORITYCLASS (0)
|
|
|
|
#define PROP_MIN__SETPROCESSUSERTIMELIMIT (0)
|
|
#define PROP_MAX__SETPROCESSUSERTIMELIMIT (1)
|
|
#define PROP_DEFAULT__SETPROCESSUSERTIMELIMIT (0)
|
|
|
|
#define PROP_MIN__PERPROCESSUSERTIMELIMIT (1)
|
|
#define PROP_MAX__PERPROCESSUSERTIMELIMIT (4294967295)
|
|
#define PROP_DEFAULT__PERPROCESSUSERTIMELIMIT (1)
|
|
|
|
#define PROP_MIN__SETSCHEDULINGCLASS (0)
|
|
#define PROP_MAX__SETSCHEDULINGCLASS (1)
|
|
#define PROP_DEFAULT__SETSCHEDULINGCLASS (0)
|
|
|
|
#define PROP_MIN__SCHEDULINGCLASS (0)
|
|
#define PROP_MAX__SCHEDULINGCLASS (9)
|
|
#define PROP_DEFAULT__SCHEDULINGCLASS (5)
|
|
|
|
#define PROP_MIN__SETWORKINGSETSIZE (0)
|
|
#define PROP_MAX__SETWORKINGSETSIZE (1)
|
|
#define PROP_DEFAULT__SETWORKINGSETSIZE (0)
|
|
|
|
#define PROP_MIN__MAXIMUMWORKINGSETSIZE (0)
|
|
#define PROP_MAX__MAXIMUMWORKINGSETSIZE (4294967295)
|
|
#define PROP_DEFAULT__MAXIMUMWORKINGSETSIZE (0)
|
|
|
|
#define PROP_MIN__MINIMUMWORKINGSETSIZE (0)
|
|
#define PROP_MAX__MINIMUMWORKINGSETSIZE (4294967295)
|
|
#define PROP_DEFAULT__MINIMUMWORKINGSETSIZE (0)
|
|
|
|
#define PROP_MIN__MANIPULATEDESKTOPS (0)
|
|
#define PROP_MAX__MANIPULATEDESKTOPS (1)
|
|
#define PROP_DEFAULT__MANIPULATEDESKTOPS (1)
|
|
|
|
#define PROP_MIN__CHANGEDISPLAYSETTINGS (0)
|
|
#define PROP_MAX__CHANGEDISPLAYSETTINGS (1)
|
|
#define PROP_DEFAULT__CHANGEDISPLAYSETTINGS (1)
|
|
|
|
#define PROP_MIN__ALLOWSYSTEMSHUTDOWN (0)
|
|
#define PROP_MAX__ALLOWSYSTEMSHUTDOWN (1)
|
|
#define PROP_DEFAULT__ALLOWSYSTEMSHUTDOWN (1)
|
|
|
|
#define PROP_MIN__ACCESSGLOBALATOMS (0)
|
|
#define PROP_MAX__ACCESSGLOBALATOMS (1)
|
|
#define PROP_DEFAULT__ACCESSGLOBALATOMS (1)
|
|
|
|
#define PROP_MIN__ALLOWOTHERPROCESSUSERHANDLES (0)
|
|
#define PROP_MAX__ALLOWOTHERPROCESSUSERHANDLES (1)
|
|
#define PROP_DEFAULT__ALLOWOTHERPROCESSUSERHANDLES (1)
|
|
|
|
#define PROP_MIN__READFROMCLIPBOARD (0)
|
|
#define PROP_MAX__READFROMCLIPBOARD (1)
|
|
#define PROP_DEFAULT__READFROMCLIPBOARD (1)
|
|
|
|
#define PROP_MIN__CHANGESYSTEMPARAMETERS (0)
|
|
#define PROP_MAX__CHANGESYSTEMPARAMETERS (1)
|
|
#define PROP_DEFAULT__CHANGESYSTEMPARAMETERS (1)
|
|
|
|
#define PROP_MIN__WRITETOCLIPBOARD (0)
|
|
#define PROP_MAX__WRITETOCLIPBOARD (1)
|
|
#define PROP_DEFAULT__WRITETOCLIPBOARD (1)
|
|
|
|
#define PROP_MIN__TERMINATEONTIMELIMIT (0)
|
|
#define PROP_MAX__TERMINATEONTIMELIMIT (1)
|
|
#define PROP_DEFAULT__TERMINATEONTIMELIMIT (1)
|
|
|
|
#define PROP_MIN__SETJOBMEMORYLIMIT (0)
|
|
#define PROP_MAX__SETJOBMEMORYLIMIT (1)
|
|
#define PROP_DEFAULT__SETJOBMEMORYLIMIT (0)
|
|
|
|
#define PROP_MIN__JOBMEMORYLIMIT (0)
|
|
#define PROP_MAX__JOBMEMORYLIMIT (4294967295)
|
|
#define PROP_DEFAULT__JOBMEMORYLIMIT (0)
|
|
|
|
#define PROP_MIN__SETPROCESSMEMORYLIMIT (0)
|
|
#define PROP_MAX__SETPROCESSMEMORYLIMIT (1)
|
|
#define PROP_DEFAULT__SETPROCESSMEMORYLIMIT (0)
|
|
|
|
#define PROP_MIN__PROCESSMEMORYLIMIT (0)
|
|
#define PROP_MAX__PROCESSMEMORYLIMIT (4294967295)
|
|
#define PROP_DEFAULT__PROCESSMEMORYLIMIT (0)
|
|
|
|
#define PROP_MIN__ALLOWLOCALADMINTOKENS (0)
|
|
#define PROP_MAX__ALLOWLOCALADMINTOKENS (1)
|
|
#define PROP_DEFAULT__ALLOWLOCALADMINTOKENS (1)
|
|
|
|
#define PROP_MIN__ALLOWUSEOFRESTRICTEDTOKENS (0)
|
|
#define PROP_MAX__ALLOWUSEOFRESTRICTEDTOKENS (1)
|
|
#define PROP_DEFAULT__ALLOWUSEOFRESTRICTEDTOKENS (1)
|
|
|
|
//
|
|
// genjob resource read-write private properties.
|
|
//
|
|
|
|
RESUTIL_PROPERTY_ITEM
|
|
GenJobResourcePrivateProperties[] = {
|
|
{ PROP_NAME__COMMANDLINE,
|
|
NULL,
|
|
CLUSPROP_FORMAT_SZ,
|
|
0, 0, 0,
|
|
RESUTIL_PROPITEM_REQUIRED,
|
|
FIELD_OFFSET(GENJOB_PROPS, CommandLine)
|
|
},
|
|
{ PROP_NAME__CURRENTDIRECTORY,
|
|
NULL,
|
|
CLUSPROP_FORMAT_SZ,
|
|
0, 0, 0,
|
|
RESUTIL_PROPITEM_REQUIRED,
|
|
FIELD_OFFSET(GENJOB_PROPS, CurrentDirectory)
|
|
},
|
|
{ PROP_NAME__INTERACTWITHDESKTOP,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__INTERACTWITHDESKTOP,
|
|
PROP_MIN__INTERACTWITHDESKTOP,
|
|
PROP_MAX__INTERACTWITHDESKTOP,
|
|
0,
|
|
FIELD_OFFSET(GENJOB_PROPS, InteractWithDesktop)
|
|
},
|
|
{ PROP_NAME__USENETWORKNAME,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__USENETWORKNAME,
|
|
PROP_MIN__USENETWORKNAME,
|
|
PROP_MAX__USENETWORKNAME,
|
|
0,
|
|
FIELD_OFFSET(GENJOB_PROPS, UseNetworkName)
|
|
},
|
|
{ PROP_NAME__USEDEFAULTS,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__USEDEFAULTS,
|
|
PROP_MIN__USEDEFAULTS,
|
|
PROP_MAX__USEDEFAULTS,
|
|
0,
|
|
FIELD_OFFSET(GENJOB_PROPS, UseDefaults)
|
|
},
|
|
|
|
{ PROP_NAME__PROCSCANBREAKAWAY,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__PROCSCANBREAKAWAY,
|
|
PROP_MIN__PROCSCANBREAKAWAY,
|
|
PROP_MAX__PROCSCANBREAKAWAY,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, ProcsCanBreakaway )
|
|
},
|
|
{ PROP_NAME__PROCSCANSILENTLYBREAKAWAY,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__PROCSCANSILENTLYBREAKAWAY,
|
|
PROP_MIN__PROCSCANSILENTLYBREAKAWAY,
|
|
PROP_MAX__PROCSCANSILENTLYBREAKAWAY,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, ProcsCanSilentlyBreakaway )
|
|
},
|
|
{ PROP_NAME__SETACTIVEPROCESSLIMIT,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__SETACTIVEPROCESSLIMIT,
|
|
PROP_MIN__SETACTIVEPROCESSLIMIT,
|
|
PROP_MAX__SETACTIVEPROCESSLIMIT,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, SetActiveProcessLimit )
|
|
},
|
|
{ PROP_NAME__ACTIVEPROCESSLIMIT,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__ACTIVEPROCESSLIMIT,
|
|
PROP_MIN__ACTIVEPROCESSLIMIT,
|
|
PROP_MAX__ACTIVEPROCESSLIMIT,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, ActiveProcessLimit )
|
|
},
|
|
#if AFFINITY_SUPPORT
|
|
{ PROP_NAME__SETAFFINITY,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__SETAFFINITY,
|
|
PROP_MIN__SETAFFINITY,
|
|
PROP_MAX__SETAFFINITY,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, SetAffinity )
|
|
},
|
|
{ PROP_NAME__AFFINITY,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__AFFINITY,
|
|
PROP_MIN__AFFINITY,
|
|
PROP_MAX__AFFINITY,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, Affinity )
|
|
},
|
|
#endif
|
|
{ PROP_NAME__SETJOBUSERTIMELIMIT,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__SETJOBUSERTIMELIMIT,
|
|
PROP_MIN__SETJOBUSERTIMELIMIT,
|
|
PROP_MAX__SETJOBUSERTIMELIMIT,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, SetJobUserTimeLimit )
|
|
},
|
|
{ PROP_NAME__PERJOBUSERTIMELIMIT,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__PERJOBUSERTIMELIMIT,
|
|
PROP_MIN__PERJOBUSERTIMELIMIT,
|
|
PROP_MAX__PERJOBUSERTIMELIMIT,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, PerJobUserTimeLimit )
|
|
},
|
|
{ PROP_NAME__SETPRIORITYCLASS,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__SETPRIORITYCLASS,
|
|
PROP_MIN__SETPRIORITYCLASS,
|
|
PROP_MAX__SETPRIORITYCLASS,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, SetPriorityClass )
|
|
},
|
|
{ PROP_NAME__PRIORITYCLASS,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__PRIORITYCLASS,
|
|
PROP_MIN__PRIORITYCLASS,
|
|
PROP_MAX__PRIORITYCLASS,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, PriorityClass )
|
|
},
|
|
{ PROP_NAME__SETPROCESSUSERTIMELIMIT,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__SETPROCESSUSERTIMELIMIT,
|
|
PROP_MIN__SETPROCESSUSERTIMELIMIT,
|
|
PROP_MAX__SETPROCESSUSERTIMELIMIT,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, SetProcessUserTimeLimit )
|
|
},
|
|
{ PROP_NAME__PERPROCESSUSERTIMELIMIT,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__PERPROCESSUSERTIMELIMIT,
|
|
PROP_MIN__PERPROCESSUSERTIMELIMIT,
|
|
PROP_MAX__PERPROCESSUSERTIMELIMIT,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, PerProcessUserTimeLimit )
|
|
},
|
|
{ PROP_NAME__SETSCHEDULINGCLASS,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__SETSCHEDULINGCLASS,
|
|
PROP_MIN__SETSCHEDULINGCLASS,
|
|
PROP_MAX__SETSCHEDULINGCLASS,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, SetSchedulingClass )
|
|
},
|
|
{ PROP_NAME__SCHEDULINGCLASS,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__SCHEDULINGCLASS,
|
|
PROP_MIN__SCHEDULINGCLASS,
|
|
PROP_MAX__SCHEDULINGCLASS,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, SchedulingClass )
|
|
},
|
|
{ PROP_NAME__SETWORKINGSETSIZE,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__SETWORKINGSETSIZE,
|
|
PROP_MIN__SETWORKINGSETSIZE,
|
|
PROP_MAX__SETWORKINGSETSIZE,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, SetWorkingSetSize )
|
|
},
|
|
{ PROP_NAME__MAXIMUMWORKINGSETSIZE,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__MAXIMUMWORKINGSETSIZE,
|
|
PROP_MIN__MAXIMUMWORKINGSETSIZE,
|
|
PROP_MAX__MAXIMUMWORKINGSETSIZE,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, MaximumWorkingSetSize )
|
|
},
|
|
{ PROP_NAME__MINIMUMWORKINGSETSIZE,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__MINIMUMWORKINGSETSIZE,
|
|
PROP_MIN__MINIMUMWORKINGSETSIZE,
|
|
PROP_MAX__MINIMUMWORKINGSETSIZE,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, MinimumWorkingSetSize )
|
|
},
|
|
|
|
{ PROP_NAME__MANIPULATEDESKTOPS,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__MANIPULATEDESKTOPS,
|
|
PROP_MIN__MANIPULATEDESKTOPS,
|
|
PROP_MAX__MANIPULATEDESKTOPS,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, ManipulateDesktops )
|
|
},
|
|
{ PROP_NAME__CHANGEDISPLAYSETTINGS,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__CHANGEDISPLAYSETTINGS,
|
|
PROP_MIN__CHANGEDISPLAYSETTINGS,
|
|
PROP_MAX__CHANGEDISPLAYSETTINGS,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, ChangeDisplaySettings )
|
|
},
|
|
{ PROP_NAME__ALLOWSYSTEMSHUTDOWN,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__ALLOWSYSTEMSHUTDOWN,
|
|
PROP_MIN__ALLOWSYSTEMSHUTDOWN,
|
|
PROP_MAX__ALLOWSYSTEMSHUTDOWN,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, AllowSystemShutdown )
|
|
},
|
|
{ PROP_NAME__ACCESSGLOBALATOMS,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__ACCESSGLOBALATOMS,
|
|
PROP_MIN__ACCESSGLOBALATOMS,
|
|
PROP_MAX__ACCESSGLOBALATOMS,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, AccessGlobalAtoms )
|
|
},
|
|
{ PROP_NAME__ALLOWOTHERPROCESSUSERHANDLES,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__ALLOWOTHERPROCESSUSERHANDLES,
|
|
PROP_MIN__ALLOWOTHERPROCESSUSERHANDLES,
|
|
PROP_MAX__ALLOWOTHERPROCESSUSERHANDLES,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, AllowOtherProcessUSERHandles )
|
|
},
|
|
{ PROP_NAME__READFROMCLIPBOARD,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__READFROMCLIPBOARD,
|
|
PROP_MIN__READFROMCLIPBOARD,
|
|
PROP_MAX__READFROMCLIPBOARD,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, ReadFromClipboard )
|
|
},
|
|
{ PROP_NAME__CHANGESYSTEMPARAMETERS,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__CHANGESYSTEMPARAMETERS,
|
|
PROP_MIN__CHANGESYSTEMPARAMETERS,
|
|
PROP_MAX__CHANGESYSTEMPARAMETERS,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, ChangeSystemParameters )
|
|
},
|
|
{ PROP_NAME__WRITETOCLIPBOARD,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__WRITETOCLIPBOARD,
|
|
PROP_MIN__WRITETOCLIPBOARD,
|
|
PROP_MAX__WRITETOCLIPBOARD,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, WriteToClipboard )
|
|
},
|
|
|
|
{ PROP_NAME__TERMINATEONTIMELIMIT,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__TERMINATEONTIMELIMIT,
|
|
PROP_MIN__TERMINATEONTIMELIMIT,
|
|
PROP_MAX__TERMINATEONTIMELIMIT,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, TerminateOnTimeLimit )
|
|
},
|
|
|
|
{ PROP_NAME__SETJOBMEMORYLIMIT,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__SETJOBMEMORYLIMIT,
|
|
PROP_MIN__SETJOBMEMORYLIMIT,
|
|
PROP_MAX__SETJOBMEMORYLIMIT,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, SetJobMemoryLimit )
|
|
},
|
|
{ PROP_NAME__JOBMEMORYLIMIT,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__JOBMEMORYLIMIT,
|
|
PROP_MIN__JOBMEMORYLIMIT,
|
|
PROP_MAX__JOBMEMORYLIMIT,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, JobMemoryLimit )
|
|
},
|
|
{ PROP_NAME__SETPROCESSMEMORYLIMIT,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__SETPROCESSMEMORYLIMIT,
|
|
PROP_MIN__SETPROCESSMEMORYLIMIT,
|
|
PROP_MAX__SETPROCESSMEMORYLIMIT,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, SetProcessMemoryLimit )
|
|
},
|
|
{ PROP_NAME__PROCESSMEMORYLIMIT,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__PROCESSMEMORYLIMIT,
|
|
PROP_MIN__PROCESSMEMORYLIMIT,
|
|
PROP_MAX__PROCESSMEMORYLIMIT,
|
|
0,
|
|
FIELD_OFFSET( GENJOB_PROPS, ProcessMemoryLimit )
|
|
},
|
|
|
|
{ PROP_NAME__ALLOWLOCALADMINTOKENS,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__ALLOWLOCALADMINTOKENS,
|
|
PROP_MIN__ALLOWLOCALADMINTOKENS,
|
|
PROP_MAX__ALLOWLOCALADMINTOKENS,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, AllowLocalAdminTokens )
|
|
},
|
|
{ PROP_NAME__ALLOWUSEOFRESTRICTEDTOKENS,
|
|
NULL,
|
|
CLUSPROP_FORMAT_DWORD,
|
|
PROP_DEFAULT__ALLOWUSEOFRESTRICTEDTOKENS,
|
|
PROP_MIN__ALLOWUSEOFRESTRICTEDTOKENS,
|
|
PROP_MAX__ALLOWUSEOFRESTRICTEDTOKENS,
|
|
RESUTIL_PROPITEM_SIGNED,
|
|
FIELD_OFFSET( GENJOB_PROPS, AllowUseOfRestrictedTokens )
|
|
},
|
|
{ 0 }
|
|
};
|
|
|
|
//
|
|
// completion port vars. A separate thread is spun up when the first resource
|
|
// goes online. This thread waits for activity on the completion port
|
|
// handle. When the last resource goes offline, the port is closed and the
|
|
// thread exits. Each time a resource comes online, it is associated with the
|
|
// port.
|
|
//
|
|
CRITICAL_SECTION GenJobPortLock;
|
|
HANDLE GenJobPort;
|
|
LONG GenJobOnlineResources = 0;
|
|
HANDLE GenJobPortThread = NULL;
|
|
|
|
// Event Logging routine
|
|
|
|
#define g_LogEvent ClusResLogEvent
|
|
#define g_SetResourceStatus ClusResSetResourceStatus
|
|
|
|
// Forward reference to our RESAPI function table.
|
|
|
|
extern CLRES_FUNCTION_TABLE GenJobFunctionTable;
|
|
|
|
|
|
//
|
|
// Forward routines
|
|
//
|
|
|
|
BOOLEAN
|
|
VerifyApp(
|
|
IN RESID ResourceId,
|
|
IN BOOLEAN IsAliveFlag
|
|
);
|
|
|
|
DWORD
|
|
GenJobGetPrivateResProperties(
|
|
IN OUT PGENJOB_RESOURCE ResourceEntry,
|
|
OUT PVOID OutBuffer,
|
|
IN DWORD OutBufferSize,
|
|
OUT LPDWORD BytesReturned
|
|
);
|
|
|
|
DWORD
|
|
GenJobValidatePrivateResProperties(
|
|
IN OUT PGENJOB_RESOURCE ResourceEntry,
|
|
IN PVOID InBuffer,
|
|
IN DWORD InBufferSize,
|
|
OUT PGENJOB_PROPS Params
|
|
);
|
|
|
|
DWORD
|
|
GenJobSetPrivateResProperties(
|
|
IN OUT PGENJOB_RESOURCE ResourceEntry,
|
|
IN PVOID InBuffer,
|
|
IN DWORD InBufferSize
|
|
);
|
|
|
|
#if LOADBAL_SUPPORT
|
|
DWORD
|
|
GenJobGetPids(
|
|
IN OUT PGENJOB_RESOURCE ResourceEntry,
|
|
OUT PVOID OutBuffer,
|
|
IN DWORD OutBufferSize,
|
|
OUT LPDWORD BytesReturned
|
|
);
|
|
#endif
|
|
|
|
VOID
|
|
GenJobTearDownCompletionPort(
|
|
VOID
|
|
);
|
|
|
|
BOOLEAN
|
|
GenJobInit(
|
|
VOID
|
|
)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOLEAN
|
|
WINAPI
|
|
GenJobDllEntryPoint(
|
|
IN HINSTANCE DllHandle,
|
|
IN DWORD Reason,
|
|
IN LPVOID Reserved
|
|
)
|
|
{
|
|
switch( Reason ) {
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
if ( !GenJobInit() ) {
|
|
return(FALSE);
|
|
}
|
|
|
|
InitializeCriticalSection( &GenJobPortLock );
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
} // GenJobDllEntryPoint
|
|
|
|
RESID
|
|
WINAPI
|
|
GenJobOpen(
|
|
IN LPCWSTR ResourceName,
|
|
IN HKEY ResourceKey,
|
|
IN RESOURCE_HANDLE ResourceHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Open routine for generic job object 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
|
|
|
|
--*/
|
|
|
|
{
|
|
RESID appResid = 0;
|
|
DWORD status;
|
|
HKEY parametersKey = NULL;
|
|
HKEY resKey = NULL;
|
|
PGENJOB_RESOURCE resourceEntry = NULL;
|
|
DWORD paramNameMaxSize = 0;
|
|
HCLUSTER hCluster;
|
|
|
|
//
|
|
// Get registry parameters for this resource.
|
|
//
|
|
status = ClusterRegOpenKey(ResourceKey,
|
|
CLUSREG_KEYNAME_PARAMETERS,
|
|
KEY_READ,
|
|
¶metersKey );
|
|
|
|
if ( status != NO_ERROR ) {
|
|
(g_LogEvent)(ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Unable to open parameters key. Error: %1!u!.\n",
|
|
status );
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// Get a handle to our resource key so that we can get our name later
|
|
// if we need to log an event.
|
|
//
|
|
status = ClusterRegOpenKey(ResourceKey,
|
|
L"",
|
|
KEY_READ,
|
|
&resKey);
|
|
if (status != ERROR_SUCCESS) {
|
|
(g_LogEvent)(ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Unable to open resource key. Error: %1!u!.\n",
|
|
status );
|
|
goto error_exit;
|
|
}
|
|
|
|
resourceEntry = LocalAlloc( LMEM_FIXED, sizeof(GENJOB_RESOURCE) );
|
|
if ( resourceEntry == NULL ) {
|
|
(g_LogEvent)(
|
|
ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Failed to allocate a process info structure.\n" );
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error_exit;
|
|
}
|
|
|
|
ZeroMemory( resourceEntry, sizeof(GENJOB_RESOURCE) );
|
|
|
|
resourceEntry->ResourceHandle = ResourceHandle;
|
|
resourceEntry->ResourceKey = resKey;
|
|
resourceEntry->ParametersKey = parametersKey;
|
|
resourceEntry->OfflineEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
if ( resourceEntry->OfflineEvent == NULL ) {
|
|
status = GetLastError();
|
|
(g_LogEvent)(ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Failed to create offline event, error %1!u!.\n",
|
|
status);
|
|
goto error_exit;
|
|
}
|
|
|
|
hCluster = OpenCluster(NULL);
|
|
if (hCluster == NULL) {
|
|
status = GetLastError();
|
|
(g_LogEvent)(ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Failed to open cluster, error %1!u!.\n",
|
|
status);
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// get a cluster resource handle to this resource
|
|
//
|
|
resourceEntry->hResource = OpenClusterResource( hCluster, ResourceName );
|
|
status = GetLastError();
|
|
CloseCluster(hCluster);
|
|
|
|
if (resourceEntry->hResource == NULL) {
|
|
(g_LogEvent)(
|
|
ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Failed to open resource, error %1!u!.\n",
|
|
status
|
|
);
|
|
goto error_exit;
|
|
}
|
|
|
|
appResid = (RESID)resourceEntry;
|
|
|
|
error_exit:
|
|
|
|
if ( appResid == NULL) {
|
|
if (parametersKey != NULL) {
|
|
ClusterRegCloseKey( parametersKey );
|
|
}
|
|
if (resKey != NULL) {
|
|
ClusterRegCloseKey( resKey );
|
|
}
|
|
}
|
|
|
|
if ( (appResid == 0) && (resourceEntry != NULL) ) {
|
|
LocalFree( resourceEntry );
|
|
}
|
|
|
|
if ( status != ERROR_SUCCESS ) {
|
|
SetLastError( status );
|
|
}
|
|
|
|
return(appResid);
|
|
|
|
} // GenJobOpen
|
|
|
|
DWORD
|
|
WINAPI
|
|
GenJobPortRoutine(
|
|
LPVOID Parameter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Monitors IO on completion port. Exits if terminate event is signalled
|
|
|
|
Arguments:
|
|
|
|
Parameter - not used
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PGENJOB_RESOURCE resource;
|
|
DWORD msgId;
|
|
DWORD msgValue;
|
|
LPWSTR logMessage;
|
|
|
|
do {
|
|
if ( GetQueuedCompletionStatus(GenJobPort,
|
|
&msgId,
|
|
(PULONG_PTR)&resource,
|
|
(LPOVERLAPPED *)&msgValue,
|
|
INFINITE))
|
|
{
|
|
if ( resource == NULL ) {
|
|
break;
|
|
}
|
|
|
|
switch ( msgId ) {
|
|
case JOB_OBJECT_MSG_END_OF_JOB_TIME:
|
|
logMessage = L"End of job time limit has been reached.\n";
|
|
break;
|
|
|
|
case JOB_OBJECT_MSG_END_OF_PROCESS_TIME:
|
|
logMessage = L"End of process time limit has been reached for process ID %1!u!.\n";
|
|
break;
|
|
|
|
case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT:
|
|
logMessage = L"The active process limit has been exceeded.\n";
|
|
break;
|
|
|
|
case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
|
|
logMessage = L"The active process count has reached zero.\n";
|
|
|
|
//
|
|
// signal that the last process in the job exited.
|
|
//
|
|
SetEvent( resource->OfflineEvent );
|
|
break;
|
|
|
|
case JOB_OBJECT_MSG_NEW_PROCESS:
|
|
logMessage = L"Process ID %1!u! has been added to the job.\n";
|
|
break;
|
|
|
|
case JOB_OBJECT_MSG_EXIT_PROCESS:
|
|
logMessage = L"Process ID %1!u! has exited.\n";
|
|
break;
|
|
|
|
case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS:
|
|
logMessage = L"Process ID %1!u! has abnormally exited.\n";
|
|
break;
|
|
|
|
case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT:
|
|
logMessage = L"Process ID %1!u! has exceeded its memory limit\n";
|
|
break;
|
|
|
|
case JOB_OBJECT_MSG_JOB_MEMORY_LIMIT:
|
|
logMessage = L"Process ID %1!u! has caused the job has to exceed its memory limit.\n";
|
|
break;
|
|
|
|
default:
|
|
(g_LogEvent)(resource->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Unknown Job message; message ID = %1!u!, msg value = %2!u!\n",
|
|
msgId,
|
|
msgValue);
|
|
|
|
goto skip_message;
|
|
}
|
|
|
|
//
|
|
// log the appropriate msg
|
|
//
|
|
(g_LogEvent)(resource->ResourceHandle,
|
|
LOG_ERROR,
|
|
logMessage,
|
|
msgValue);
|
|
skip_message:
|
|
;
|
|
}
|
|
} while (1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DWORD
|
|
GenJobInitializeCompletionPort(
|
|
IN RESOURCE_HANDLE ResourceHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Init all the giblets associatd with the completion port, i.e., create the
|
|
port, spin up the thread that waits on the port, etc. Must be called with
|
|
GenJobPortLock held.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if everything worked
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status = ERROR_SUCCESS;
|
|
DWORD threadId;
|
|
|
|
//
|
|
// create the completion port
|
|
//
|
|
GenJobPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 );
|
|
|
|
if ( GenJobPort == NULL ) {
|
|
status = GetLastError();
|
|
(g_LogEvent)(ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Unable to create completion port. Error: %1!u!.\n",
|
|
status );
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// create the thread that waits on the port
|
|
//
|
|
GenJobPortThread = CreateThread(NULL, // default security
|
|
0, // default stack
|
|
GenJobPortRoutine,
|
|
0, // routine parameter
|
|
0, // creation flags
|
|
&threadId);
|
|
|
|
if ( GenJobPortThread == NULL ) {
|
|
status = GetLastError();
|
|
(g_LogEvent)(ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Unable to create completion port thread. Error: %1!u!.\n",
|
|
status );
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
DWORD
|
|
SetJobObjectClasses(
|
|
IN PGENJOB_RESOURCE ResourceEntry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
build the job object class struct from the operational data in the
|
|
resource entry and call SetInformationJobObject
|
|
|
|
Arguments:
|
|
|
|
ResourceEntry - pointer to netname resource being manipulated
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if everything worked ok
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status = ERROR_SUCCESS;
|
|
PGENJOB_PROPS jobProps = &ResourceEntry->OperationalProps;
|
|
JOBOBJECT_BASIC_UI_RESTRICTIONS basicUiLimits;
|
|
JOBOBJECT_END_OF_JOB_TIME_INFORMATION timeLimits;
|
|
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedLimits;
|
|
JOBOBJECT_SECURITY_LIMIT_INFORMATION securityLimits;
|
|
|
|
//
|
|
// init various flag members to their defaults
|
|
//
|
|
basicUiLimits.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE;
|
|
securityLimits.SecurityLimitFlags = 0;
|
|
extendedLimits.BasicLimitInformation.LimitFlags =
|
|
JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
|
|
timeLimits.EndOfJobTimeAction = JOB_OBJECT_TERMINATE_AT_END_OF_JOB;
|
|
|
|
if ( !jobProps->UseDefaults ) {
|
|
|
|
//
|
|
// set basic limits. convert time limits from secs to 100ns units
|
|
//
|
|
if ( jobProps->SetProcessUserTimeLimit ) {
|
|
extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_TIME;
|
|
extendedLimits.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart =
|
|
jobProps->PerProcessUserTimeLimit * 10 * 1000 * 1000;
|
|
}
|
|
|
|
if ( jobProps->SetJobUserTimeLimit ) {
|
|
extendedLimits.BasicLimitInformation.LimitFlags |=
|
|
JOB_OBJECT_LIMIT_JOB_TIME;
|
|
extendedLimits.BasicLimitInformation.PerJobUserTimeLimit.QuadPart =
|
|
jobProps->PerJobUserTimeLimit * 10 * 1000 * 1000;
|
|
}
|
|
|
|
if ( jobProps->SetWorkingSetSize ) {
|
|
extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_WORKINGSET;
|
|
extendedLimits.BasicLimitInformation.MinimumWorkingSetSize = jobProps->MinimumWorkingSetSize;
|
|
extendedLimits.BasicLimitInformation.MaximumWorkingSetSize = jobProps->MaximumWorkingSetSize;
|
|
}
|
|
|
|
if ( jobProps->SetActiveProcessLimit ) {
|
|
extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
|
|
extendedLimits.BasicLimitInformation.ActiveProcessLimit = jobProps->ActiveProcessLimit;
|
|
}
|
|
|
|
#if 0
|
|
if ( jobProps->SetAffininty ) {
|
|
extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_AFFINITY;
|
|
extendedLimits.BasicLimitInformation.Affinity = jobProps->Affinity;
|
|
}
|
|
#endif
|
|
|
|
if ( jobProps->SetPriorityClass ) {
|
|
extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
|
|
extendedLimits.BasicLimitInformation.PriorityClass = jobProps->PriorityClass;
|
|
}
|
|
|
|
if ( jobProps->SetSchedulingClass ) {
|
|
extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_SCHEDULING_CLASS;
|
|
extendedLimits.BasicLimitInformation.SchedulingClass = jobProps->SchedulingClass;
|
|
}
|
|
|
|
if ( jobProps->ProcsCanBreakaway ) {
|
|
extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK;
|
|
}
|
|
|
|
if ( jobProps->ProcsCanSilentlyBreakaway ) {
|
|
extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
|
|
}
|
|
|
|
//
|
|
// basic UI limits
|
|
//
|
|
if ( !jobProps->ManipulateDesktops ) {
|
|
basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_DESKTOP;
|
|
}
|
|
if ( !jobProps->ChangeDisplaySettings ) {
|
|
basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_DISPLAYSETTINGS;
|
|
}
|
|
if ( !jobProps->AllowSystemShutdown ) {
|
|
basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;
|
|
}
|
|
if ( !jobProps->AccessGlobalAtoms ) {
|
|
basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_GLOBALATOMS;
|
|
}
|
|
if ( !jobProps->AllowOtherProcessUSERHandles ) {
|
|
basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
|
|
}
|
|
if ( !jobProps->ReadFromClipboard ) {
|
|
basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_READCLIPBOARD;
|
|
}
|
|
if ( !jobProps->ChangeSystemParameters ) {
|
|
basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS;
|
|
}
|
|
if ( !jobProps->WriteToClipboard ) {
|
|
basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
|
|
}
|
|
|
|
//
|
|
// time limits
|
|
//
|
|
if ( !jobProps->TerminateOnTimeLimit ) {
|
|
timeLimits.EndOfJobTimeAction = JOB_OBJECT_POST_AT_END_OF_JOB;
|
|
}
|
|
|
|
//
|
|
// extended limits
|
|
//
|
|
if ( jobProps->SetProcessMemoryLimit ) {
|
|
extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_MEMORY;
|
|
extendedLimits.ProcessMemoryLimit = jobProps->ProcessMemoryLimit;
|
|
}
|
|
|
|
if ( jobProps->SetJobMemoryLimit ) {
|
|
extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_MEMORY;
|
|
extendedLimits.JobMemoryLimit = jobProps->JobMemoryLimit;
|
|
}
|
|
|
|
//
|
|
// security limits
|
|
//
|
|
if ( !jobProps->AllowUseOfRestrictedTokens ) {
|
|
securityLimits.SecurityLimitFlags |= JOB_OBJECT_SECURITY_RESTRICTED_TOKEN;
|
|
}
|
|
|
|
if ( !jobProps->AllowLocalAdminTokens ) {
|
|
securityLimits.SecurityLimitFlags |= JOB_OBJECT_SECURITY_NO_ADMIN;
|
|
}
|
|
}
|
|
|
|
//
|
|
// extended limits which includes basic. we always do this since there are
|
|
// some basic limit flags we want to set regardless of whether defaults
|
|
// are used
|
|
//
|
|
if ( !SetInformationJobObject(ResourceEntry->JobHandle,
|
|
JobObjectExtendedLimitInformation,
|
|
&extendedLimits,
|
|
sizeof( extendedLimits )))
|
|
{
|
|
status = GetLastError();
|
|
(g_LogEvent)(ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't set extended limit information. Error: %1!u!.\n",
|
|
status );
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// set the other limits as appropriate
|
|
//
|
|
if ( !SetInformationJobObject(ResourceEntry->JobHandle,
|
|
JobObjectBasicUIRestrictions,
|
|
&basicUiLimits,
|
|
sizeof( basicUiLimits )))
|
|
{
|
|
status = GetLastError();
|
|
(g_LogEvent)(ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't set basic UI limit information. Error: %1!u!.\n",
|
|
status );
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// time is special in that we only set if they want something other than
|
|
// the default
|
|
//
|
|
if ( !SetInformationJobObject(ResourceEntry->JobHandle,
|
|
JobObjectEndOfJobTimeInformation,
|
|
&timeLimits,
|
|
sizeof( timeLimits )))
|
|
{
|
|
status = GetLastError();
|
|
(g_LogEvent)(ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't set end of job time information. Error: %1!u!.\n",
|
|
status );
|
|
goto error_exit;
|
|
}
|
|
|
|
if ( !SetInformationJobObject(ResourceEntry->JobHandle,
|
|
JobObjectSecurityLimitInformation,
|
|
&securityLimits,
|
|
sizeof( securityLimits )))
|
|
{
|
|
status = GetLastError();
|
|
(g_LogEvent)(ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't set security limit information. Error: %1!u!.\n",
|
|
status );
|
|
}
|
|
|
|
error_exit:
|
|
|
|
return status;
|
|
}
|
|
|
|
DWORD
|
|
GenJobOnlineThread(
|
|
IN PCLUS_WORKER pWorker,
|
|
IN PGENJOB_RESOURCE ResourceEntry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Brings a disk resource online.
|
|
|
|
Arguments:
|
|
|
|
Worker - Supplies the worker structure
|
|
|
|
Context - A pointer to the GenJob block for this resource.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
Win32 error code on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
RESOURCE_STATUS resourceStatus;
|
|
DWORD status = ERROR_SUCCESS;
|
|
STARTUPINFO startupInfo;
|
|
PROCESS_INFORMATION processInfo;
|
|
LPWSTR nameOfPropInError;
|
|
LPVOID Environment = NULL;
|
|
JOBOBJECT_ASSOCIATE_COMPLETION_PORT portInfo;
|
|
|
|
//
|
|
// initial resource status struct
|
|
//
|
|
ResUtilInitializeResourceStatus( &resourceStatus );
|
|
|
|
resourceStatus.ResourceState = ClusterResourceFailed;
|
|
//resourceStatus.WaitHint = 0;
|
|
resourceStatus.CheckPoint = 1;
|
|
|
|
//
|
|
// create the unnamed completion port if necessary. If online fails at
|
|
// some point, resmon will call GenJobTerminate which decrements the count
|
|
//
|
|
EnterCriticalSection( &GenJobPortLock );
|
|
if ( ++GenJobOnlineResources == 1 ) {
|
|
status = GenJobInitializeCompletionPort( ResourceEntry->ResourceHandle );
|
|
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(g_LogEvent)(ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Unable to create completon port. Error: %1!u!.\n",
|
|
status );
|
|
|
|
LeaveCriticalSection( &GenJobPortLock );
|
|
goto error_exit;
|
|
}
|
|
}
|
|
LeaveCriticalSection( &GenJobPortLock );
|
|
|
|
//
|
|
// create an un-named job object
|
|
//
|
|
ResourceEntry->JobHandle = CreateJobObject( NULL, NULL );
|
|
if ( ResourceEntry->JobHandle == NULL ) {
|
|
status = GetLastError();
|
|
(g_LogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Unable to create job object. Error: %1!u!.\n",
|
|
status );
|
|
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// Read our parameters.
|
|
//
|
|
status = ResUtilGetPropertiesToParameterBlock( ResourceEntry->ParametersKey,
|
|
GenJobResourcePrivateProperties,
|
|
(LPBYTE) &ResourceEntry->OperationalProps,
|
|
TRUE, // CheckForRequiredProperties
|
|
&nameOfPropInError );
|
|
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(g_LogEvent)(ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Unable to read the '%1' property. Error: %2!u!.\n",
|
|
(nameOfPropInError == NULL ? L"" : nameOfPropInError),
|
|
status );
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// move our prop values into the job object structs
|
|
//
|
|
status = SetJobObjectClasses( ResourceEntry );
|
|
if ( status != ERROR_SUCCESS ) {
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// set the job object completion port data
|
|
//
|
|
portInfo.CompletionKey = ResourceEntry;
|
|
portInfo.CompletionPort = GenJobPort;
|
|
if ( !SetInformationJobObject(ResourceEntry->JobHandle,
|
|
JobObjectAssociateCompletionPortInformation,
|
|
&portInfo,
|
|
sizeof( portInfo )))
|
|
{
|
|
status = GetLastError();
|
|
(g_LogEvent)(ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Unable to associate completion port with job. Error: %1!u!.\n",
|
|
status );
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// fake the network name if told to
|
|
//
|
|
if ( ResourceEntry->OperationalProps.UseNetworkName ) {
|
|
Environment = ResUtilGetEnvironmentWithNetName( ResourceEntry->hResource );
|
|
}
|
|
|
|
//
|
|
// fire it up!
|
|
//
|
|
ZeroMemory( &startupInfo, sizeof(startupInfo) );
|
|
startupInfo.cb = sizeof(startupInfo);
|
|
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
|
|
|
|
if ( ResourceEntry->OperationalProps.InteractWithDesktop ) {
|
|
startupInfo.lpDesktop = L"WinSta0\\Default";
|
|
startupInfo.wShowWindow = SW_SHOW;
|
|
} else {
|
|
startupInfo.wShowWindow = SW_HIDE;
|
|
}
|
|
|
|
if ( !CreateProcess( NULL,
|
|
ResourceEntry->OperationalProps.CommandLine,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_UNICODE_ENVIRONMENT,
|
|
Environment,
|
|
ResourceEntry->OperationalProps.CurrentDirectory,
|
|
&startupInfo,
|
|
&processInfo))
|
|
{
|
|
status = GetLastError();
|
|
ClusResLogSystemEventByKeyData(ResourceEntry->ResourceKey,
|
|
LOG_CRITICAL,
|
|
RES_GENJOB_CREATE_FAILED,
|
|
sizeof(status),
|
|
&status);
|
|
|
|
(g_LogEvent)(ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Failed to create process. Error: %1!u!.\n",
|
|
status );
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// associate the proc with the job
|
|
//
|
|
if ( !AssignProcessToJobObject(ResourceEntry->JobHandle,
|
|
processInfo.hProcess))
|
|
{
|
|
status = GetLastError();
|
|
(g_LogEvent)(ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Failed to assign process to job. Error: %1!u!.\n",
|
|
status );
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// Save the process Id and close the process/thread handles
|
|
//
|
|
ResourceEntry->ProcessId = processInfo.dwProcessId;
|
|
CloseHandle( processInfo.hThread );
|
|
CloseHandle( processInfo.hProcess );
|
|
|
|
ResourceEntry->Online = TRUE;
|
|
|
|
//
|
|
// job objects are signalled only when a limit is exceeded so an event is
|
|
// used to indicate when the last process in the job has exited.
|
|
//
|
|
resourceStatus.EventHandle = ResourceEntry->OfflineEvent;
|
|
resourceStatus.ResourceState = ClusterResourceOnline;
|
|
|
|
error_exit:
|
|
|
|
(g_SetResourceStatus)( ResourceEntry->ResourceHandle,
|
|
&resourceStatus );
|
|
|
|
if ( resourceStatus.ResourceState == ClusterResourceOnline ) {
|
|
ResourceEntry->Online = TRUE;
|
|
} else {
|
|
ResourceEntry->Online = FALSE;
|
|
}
|
|
|
|
if (Environment != NULL) {
|
|
RtlDestroyEnvironment(Environment);
|
|
}
|
|
|
|
return(status);
|
|
|
|
} // GenJobOnlineThread
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
GenJobOnline(
|
|
IN RESID ResourceId,
|
|
IN OUT PHANDLE EventHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Online routine for Generic Job Object resource.
|
|
|
|
Arguments:
|
|
|
|
ResourceId - 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PGENJOB_RESOURCE resourceEntry;
|
|
DWORD status = ERROR_SUCCESS;
|
|
|
|
resourceEntry = (PGENJOB_RESOURCE)ResourceId;
|
|
|
|
if ( resourceEntry == NULL ) {
|
|
DBG_PRINT( "GenJob: Online request for a nonexistent resource id 0x%p.\n",
|
|
ResourceId );
|
|
return(ERROR_RESOURCE_NOT_FOUND);
|
|
}
|
|
|
|
if ( resourceEntry->JobHandle != NULL ) {
|
|
(g_LogEvent)(
|
|
resourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Online request and job object handle is not NULL!\n" );
|
|
return(ERROR_NOT_READY);
|
|
}
|
|
|
|
(g_LogEvent)(resourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Online request.\n");
|
|
|
|
ClusWorkerTerminate( &resourceEntry->OnlineThread );
|
|
status = ClusWorkerCreate( &resourceEntry->OnlineThread,
|
|
GenJobOnlineThread,
|
|
resourceEntry );
|
|
|
|
if ( status == ERROR_SUCCESS ) {
|
|
status = ERROR_IO_PENDING;
|
|
}
|
|
|
|
return(status);
|
|
|
|
} // GenJobOnline
|
|
|
|
VOID
|
|
GenJobTearDownCompletionPort(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clean up all the mechanisms associated with the completion port. Must be
|
|
called with GenJobPortLock critsec held.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
|
|
//
|
|
// setting lpOverlapped to NULL signals the GenJobPortRoutine to exit
|
|
//
|
|
if ( GenJobPortThread != NULL ) {
|
|
PostQueuedCompletionStatus( GenJobPort, 0, 0, NULL );
|
|
status = WaitForSingleObject( GenJobPortThread, INFINITE );
|
|
CloseHandle( GenJobPortThread );
|
|
GenJobPortThread = NULL;
|
|
}
|
|
|
|
if ( GenJobPort != NULL ) {
|
|
CloseHandle( GenJobPort );
|
|
GenJobPort = NULL;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
GenJobTerminate(
|
|
IN RESID ResourceId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Terminate routine for Generic Job Object resource.
|
|
|
|
Arguments:
|
|
|
|
ResourceId - Supplies resource id to be terminated
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PGENJOB_RESOURCE resourceEntry;
|
|
DWORD status;
|
|
|
|
resourceEntry = (PGENJOB_RESOURCE)ResourceId;
|
|
|
|
if ( resourceEntry == NULL ) {
|
|
DBG_PRINT( "GenJob: Terminate request for a nonexistent resource id 0x%p\n",
|
|
ResourceId );
|
|
return;
|
|
}
|
|
|
|
if ( !TerminateJobObject( resourceEntry->JobHandle, 1 ) ) {
|
|
status = GetLastError();
|
|
if ( status != ERROR_ACCESS_DENIED ) {
|
|
(g_LogEvent)(
|
|
resourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Failed to terminate job object, handle %1!u!. Error: %2!u!.\n",
|
|
resourceEntry->JobHandle,
|
|
status );
|
|
}
|
|
}
|
|
|
|
CloseHandle( resourceEntry->JobHandle );
|
|
resourceEntry->JobHandle = NULL;
|
|
|
|
//
|
|
// get rid of the completion port if there are no more open resources
|
|
//
|
|
if ( resourceEntry->Online == TRUE ) {
|
|
EnterCriticalSection( &GenJobPortLock );
|
|
ASSERT( GenJobOnlineResources > 0 );
|
|
if ( --GenJobOnlineResources == 0 ) {
|
|
GenJobTearDownCompletionPort();
|
|
}
|
|
LeaveCriticalSection( &GenJobPortLock );
|
|
}
|
|
|
|
resourceEntry->Online = FALSE;
|
|
|
|
} // GenJobTerminate
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
GenJobOffline(
|
|
IN RESID ResourceId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Offline routine for Generic Job Object resource.
|
|
|
|
Arguments:
|
|
|
|
ResourceId - Supplies the resource to be taken offline
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - always successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
PGENJOB_RESOURCE resourceEntry = (PGENJOB_RESOURCE)ResourceId;
|
|
|
|
(g_LogEvent)(resourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Offline request.\n");
|
|
|
|
GenJobTerminate( ResourceId );
|
|
|
|
return(ERROR_SUCCESS);
|
|
|
|
} // GenJobOffline
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
GenJobIsAlive(
|
|
IN RESID ResourceId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IsAlive routine for Generice job object resource.
|
|
|
|
Arguments:
|
|
|
|
ResourceId - Supplies the resource id to be polled.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Resource is alive and well
|
|
|
|
FALSE - Resource is toast.
|
|
|
|
--*/
|
|
|
|
{
|
|
return VerifyApp( ResourceId, TRUE );
|
|
|
|
} // GenJobIsAlive
|
|
|
|
|
|
BOOLEAN
|
|
VerifyApp(
|
|
IN RESID ResourceId,
|
|
IN BOOLEAN IsAliveFlag
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verify that a Generic Job Objects resource is running
|
|
|
|
Arguments:
|
|
|
|
ResourceId - Supplies the resource id to be polled.
|
|
|
|
IsAliveFlag - TRUE if called from IsAlive, otherwise called from LooksAlive.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Resource is alive and well
|
|
|
|
FALSE - Resource is toast.
|
|
|
|
--*/
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
} // VerifyApp
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
GenJobLooksAlive(
|
|
IN RESID ResourceId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
LooksAlive routine for Generic Job Objects resource.
|
|
|
|
Arguments:
|
|
|
|
ResourceId - 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
return VerifyApp( ResourceId, FALSE );
|
|
|
|
} // GenJobLooksAlive
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
GenJobClose(
|
|
IN RESID ResourceId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Close routine for Generic Job Objects resource.
|
|
|
|
Arguments:
|
|
|
|
ResourceId - Supplies resource id to be closed
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PGENJOB_RESOURCE resourceEntry;
|
|
DWORD status;
|
|
|
|
resourceEntry = (PGENJOB_RESOURCE)ResourceId;
|
|
if ( resourceEntry == NULL ) {
|
|
DBG_PRINT( "GenJob: Close request for a nonexistent resource id 0x%p\n",
|
|
ResourceId );
|
|
return;
|
|
}
|
|
|
|
ClusterRegCloseKey( resourceEntry->ParametersKey );
|
|
ClusterRegCloseKey( resourceEntry->ResourceKey );
|
|
CloseClusterResource( resourceEntry->hResource );
|
|
|
|
CloseHandle( resourceEntry->OfflineEvent );
|
|
|
|
LocalFree( resourceEntry->OperationalProps.CommandLine );
|
|
LocalFree( resourceEntry->OperationalProps.CurrentDirectory );
|
|
|
|
LocalFree( resourceEntry );
|
|
|
|
} // GenJobClose
|
|
|
|
|
|
DWORD
|
|
GenJobResourceControl(
|
|
IN RESID ResourceId,
|
|
IN DWORD ControlCode,
|
|
IN PVOID InBuffer,
|
|
IN DWORD InBufferSize,
|
|
OUT PVOID OutBuffer,
|
|
IN DWORD OutBufferSize,
|
|
OUT LPDWORD BytesReturned
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ResourceControl routine for Generic Job Object resources.
|
|
|
|
Perform the control request specified by ControlCode on the specified
|
|
resource.
|
|
|
|
Arguments:
|
|
|
|
ResourceId - Supplies the resource id for the specific resource.
|
|
|
|
ControlCode - Supplies the control code that defines the action
|
|
to be performed.
|
|
|
|
InBuffer - Supplies a pointer to a buffer containing input data.
|
|
|
|
InBufferSize - Supplies the size, in bytes, of the data pointed
|
|
to by InBuffer.
|
|
|
|
OutBuffer - Supplies a pointer to the output buffer to be filled in.
|
|
|
|
OutBufferSize - Supplies the size, in bytes, of the available space
|
|
pointed to by OutBuffer.
|
|
|
|
BytesReturned - Returns the number of bytes of OutBuffer actually
|
|
filled in by the resource. If OutBuffer is too small, BytesReturned
|
|
contains the total number of bytes for the operation to succeed.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - The function completed successfully.
|
|
|
|
ERROR_INVALID_FUNCTION - The requested control code is not supported.
|
|
In some cases, this allows the cluster software to perform the work.
|
|
|
|
Win32 error code - The function failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
PGENJOB_RESOURCE resourceEntry;
|
|
DWORD required;
|
|
|
|
resourceEntry = (PGENJOB_RESOURCE)ResourceId;
|
|
|
|
if ( resourceEntry == NULL ) {
|
|
DBG_PRINT( "GenJob: ResourceControl request for a nonexistent resource id 0x%p\n",
|
|
ResourceId );
|
|
return(FALSE);
|
|
}
|
|
|
|
switch ( ControlCode ) {
|
|
|
|
case CLUSCTL_RESOURCE_UNKNOWN:
|
|
*BytesReturned = 0;
|
|
status = ERROR_SUCCESS;
|
|
break;
|
|
|
|
case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS:
|
|
status = ResUtilGetPropertyFormats( GenJobResourcePrivateProperties,
|
|
OutBuffer,
|
|
OutBufferSize,
|
|
BytesReturned,
|
|
&required );
|
|
if ( status == ERROR_MORE_DATA ) {
|
|
*BytesReturned = required;
|
|
}
|
|
break;
|
|
|
|
|
|
case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
|
|
status = ResUtilEnumProperties( GenJobResourcePrivateProperties,
|
|
OutBuffer,
|
|
OutBufferSize,
|
|
BytesReturned,
|
|
&required );
|
|
if ( status == ERROR_MORE_DATA ) {
|
|
*BytesReturned = required;
|
|
}
|
|
break;
|
|
|
|
case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
|
|
status = GenJobGetPrivateResProperties( resourceEntry,
|
|
OutBuffer,
|
|
OutBufferSize,
|
|
BytesReturned );
|
|
break;
|
|
|
|
case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
|
|
status = GenJobValidatePrivateResProperties( resourceEntry,
|
|
InBuffer,
|
|
InBufferSize,
|
|
NULL );
|
|
break;
|
|
|
|
case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
|
|
status = GenJobSetPrivateResProperties( resourceEntry,
|
|
InBuffer,
|
|
InBufferSize );
|
|
break;
|
|
|
|
#if LOADBAL_SUPPORT
|
|
case CLUSCTL_RESOURCE_GET_LOADBAL_PROCESS_LIST:
|
|
status = GenJobGetPids( resourceEntry,
|
|
OutBuffer,
|
|
OutBufferSize,
|
|
BytesReturned );
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
status = ERROR_INVALID_FUNCTION;
|
|
break;
|
|
}
|
|
|
|
return(status);
|
|
|
|
} // GenJobResourceControl
|
|
|
|
|
|
DWORD
|
|
GenJobResourceTypeControl(
|
|
IN LPCWSTR ResourceTypeName,
|
|
IN DWORD ControlCode,
|
|
IN PVOID InBuffer,
|
|
IN DWORD InBufferSize,
|
|
OUT PVOID OutBuffer,
|
|
IN DWORD OutBufferSize,
|
|
OUT LPDWORD BytesReturned
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ResourceTypeControl routine for Generic Job Object resources.
|
|
|
|
Perform the control request specified by ControlCode for this resource type.
|
|
|
|
Arguments:
|
|
|
|
ResourceTypeName - Supplies the resource type name.
|
|
|
|
ControlCode - Supplies the control code that defines the action
|
|
to be performed.
|
|
|
|
InBuffer - Supplies a pointer to a buffer containing input data.
|
|
|
|
InBufferSize - Supplies the size, in bytes, of the data pointed
|
|
to by InBuffer.
|
|
|
|
OutBuffer - Supplies a pointer to the output buffer to be filled in.
|
|
|
|
OutBufferSize - Supplies the size, in bytes, of the available space
|
|
pointed to by OutBuffer.
|
|
|
|
BytesReturned - Returns the number of bytes of OutBuffer actually
|
|
filled in by the resource. If OutBuffer is too small, BytesReturned
|
|
contains the total number of bytes for the operation to succeed.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - The function completed successfully.
|
|
|
|
ERROR_INVALID_FUNCTION - The requested control code is not supported.
|
|
In some cases, this allows the cluster software to perform the work.
|
|
|
|
Win32 error code - The function failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
DWORD required;
|
|
|
|
switch ( ControlCode ) {
|
|
|
|
case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
|
|
*BytesReturned = 0;
|
|
status = ERROR_SUCCESS;
|
|
break;
|
|
|
|
case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS:
|
|
status = ResUtilGetPropertyFormats( GenJobResourcePrivateProperties,
|
|
OutBuffer,
|
|
OutBufferSize,
|
|
BytesReturned,
|
|
&required );
|
|
if ( status == ERROR_MORE_DATA ) {
|
|
*BytesReturned = required;
|
|
}
|
|
break;
|
|
|
|
|
|
case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
|
|
status = ResUtilEnumProperties( GenJobResourcePrivateProperties,
|
|
OutBuffer,
|
|
OutBufferSize,
|
|
BytesReturned,
|
|
&required );
|
|
if ( status == ERROR_MORE_DATA ) {
|
|
*BytesReturned = required;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
status = ERROR_INVALID_FUNCTION;
|
|
break;
|
|
}
|
|
|
|
return(status);
|
|
|
|
} // GenJobResourceTypeControl
|
|
|
|
|
|
DWORD
|
|
GenJobGetPrivateResProperties(
|
|
IN OUT PGENJOB_RESOURCE ResourceEntry,
|
|
OUT PVOID OutBuffer,
|
|
IN DWORD OutBufferSize,
|
|
OUT LPDWORD BytesReturned
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
|
|
for resources of type GenJob.
|
|
|
|
Arguments:
|
|
|
|
ResourceEntry - Supplies the resource entry on which to operate.
|
|
|
|
OutBuffer - Returns the output data.
|
|
|
|
OutBufferSize - Supplies the size, in bytes, of the data pointed
|
|
to by OutBuffer.
|
|
|
|
BytesReturned - The number of bytes returned in OutBuffer.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - The function completed successfully.
|
|
|
|
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
|
|
|
|
Win32 error code - The function failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
DWORD required;
|
|
|
|
status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
|
|
GenJobResourcePrivateProperties,
|
|
OutBuffer,
|
|
OutBufferSize,
|
|
BytesReturned,
|
|
&required );
|
|
if ( status == ERROR_MORE_DATA ) {
|
|
*BytesReturned = required;
|
|
}
|
|
|
|
return(status);
|
|
|
|
} // GenJobGetPrivateResProperties
|
|
|
|
|
|
DWORD
|
|
GenJobValidatePrivateResProperties(
|
|
IN OUT PGENJOB_RESOURCE ResourceEntry,
|
|
IN PVOID InBuffer,
|
|
IN DWORD InBufferSize,
|
|
OUT PGENJOB_PROPS Params
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
|
|
function for resources of type Generic Job Object.
|
|
|
|
Arguments:
|
|
|
|
ResourceEntry - Supplies the resource entry on which to operate.
|
|
|
|
InBuffer - Supplies a pointer to a buffer containing input data.
|
|
|
|
InBufferSize - Supplies the size, in bytes, of the data pointed
|
|
to by InBuffer.
|
|
|
|
Params - Supplies the parameter block to fill in.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - The function completed successfully.
|
|
|
|
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
|
|
|
|
ERROR_DEPENDENCY_NOT_FOUND - Trying to set UseNetworkName when there
|
|
is no dependency on a Network Name resource.
|
|
|
|
Win32 error code - The function failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
GENJOB_PROPS currentProps;
|
|
GENJOB_PROPS newProps;
|
|
PGENJOB_PROPS pParams;
|
|
HRESOURCE hResDependency;
|
|
LPWSTR nameOfPropInError;
|
|
|
|
//
|
|
// Check if there is input data.
|
|
//
|
|
if ( (InBuffer == NULL) ||
|
|
(InBufferSize < sizeof(DWORD)) ) {
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
//
|
|
// Retrieve the current set of private properties from the
|
|
// cluster database.
|
|
//
|
|
ZeroMemory( ¤tProps, sizeof(currentProps) );
|
|
|
|
status = ResUtilGetPropertiesToParameterBlock(
|
|
ResourceEntry->ParametersKey,
|
|
GenJobResourcePrivateProperties,
|
|
(LPBYTE) ¤tProps,
|
|
FALSE, /*CheckForRequiredProperties*/
|
|
&nameOfPropInError
|
|
);
|
|
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(g_LogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Unable to read the '%1' property. Error: %2!u!.\n",
|
|
(nameOfPropInError == NULL ? L"" : nameOfPropInError),
|
|
status );
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Duplicate the resource parameter block.
|
|
//
|
|
if ( Params == NULL ) {
|
|
pParams = &newProps;
|
|
} else {
|
|
pParams = Params;
|
|
}
|
|
ZeroMemory( pParams, sizeof(GENJOB_PROPS) );
|
|
status = ResUtilDupParameterBlock( (LPBYTE) pParams,
|
|
(LPBYTE) ¤tProps,
|
|
GenJobResourcePrivateProperties );
|
|
if ( status != ERROR_SUCCESS ) {
|
|
return(status);
|
|
}
|
|
|
|
//
|
|
// Parse and validate the properties.
|
|
//
|
|
status = ResUtilVerifyPropertyTable( GenJobResourcePrivateProperties,
|
|
NULL,
|
|
TRUE, // Allow unknowns
|
|
InBuffer,
|
|
InBufferSize,
|
|
(LPBYTE) pParams );
|
|
|
|
if ( status == ERROR_SUCCESS ) {
|
|
//
|
|
// Validate the CurrentDirectory
|
|
//
|
|
if ( pParams->CurrentDirectory &&
|
|
!ResUtilIsPathValid( pParams->CurrentDirectory ) ) {
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// If the resource should use the network name as the computer
|
|
// name, make sure there is a dependency on a Network Name
|
|
// resource.
|
|
//
|
|
if ( pParams->UseNetworkName ) {
|
|
hResDependency = ResUtilGetResourceDependency(ResourceEntry->hResource,
|
|
CLUS_RESTYPE_NAME_NETNAME);
|
|
if ( hResDependency == NULL ) {
|
|
status = ERROR_DEPENDENCY_NOT_FOUND;
|
|
} else {
|
|
CloseClusterResource( hResDependency );
|
|
}
|
|
}
|
|
}
|
|
|
|
FnExit:
|
|
//
|
|
// Cleanup our parameter block.
|
|
//
|
|
if ( ( (status != ERROR_SUCCESS)
|
|
&& (pParams != NULL) )
|
|
|| ( pParams == &newProps )
|
|
) {
|
|
ResUtilFreeParameterBlock( (LPBYTE) &pParams,
|
|
(LPBYTE) ¤tProps,
|
|
GenJobResourcePrivateProperties );
|
|
}
|
|
|
|
ResUtilFreeParameterBlock(
|
|
(LPBYTE) ¤tProps,
|
|
NULL,
|
|
GenJobResourcePrivateProperties
|
|
);
|
|
|
|
return(status);
|
|
|
|
} // GenJobValidatePrivateResProperties
|
|
|
|
|
|
DWORD
|
|
GenJobSetPrivateResProperties(
|
|
IN OUT PGENJOB_RESOURCE ResourceEntry,
|
|
IN PVOID InBuffer,
|
|
IN DWORD InBufferSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function for
|
|
resources of type Generic Job Object. Some parameters (command line,
|
|
current dir, desktop, and netname) cause no change in the resource if it
|
|
is online and the parameters have changed value. If any job object
|
|
parameters are specified at the same time, they DO NOT get set.
|
|
|
|
Arguments:
|
|
|
|
ResourceEntry - Supplies the resource entry on which to operate.
|
|
|
|
InBuffer - Supplies a pointer to a buffer containing input data.
|
|
|
|
InBufferSize - Supplies the size, in bytes, of the data pointed
|
|
to by InBuffer.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - The function completed successfully.
|
|
|
|
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
|
|
|
|
Win32 error code - The function failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
GENJOB_PROPS params;
|
|
|
|
ZeroMemory( ¶ms, sizeof(GENJOB_PROPS) );
|
|
|
|
//
|
|
// Parse and validate the properties.
|
|
//
|
|
status = GenJobValidatePrivateResProperties( ResourceEntry,
|
|
InBuffer,
|
|
InBufferSize,
|
|
¶ms );
|
|
if ( status != ERROR_SUCCESS ) {
|
|
return(status);
|
|
}
|
|
|
|
//
|
|
// Save the parameter values.
|
|
//
|
|
status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
|
|
GenJobResourcePrivateProperties,
|
|
NULL,
|
|
(LPBYTE) ¶ms,
|
|
InBuffer,
|
|
InBufferSize,
|
|
(LPBYTE) &ResourceEntry->StoredProps );
|
|
|
|
ResUtilFreeParameterBlock( (LPBYTE) ¶ms,
|
|
(LPBYTE) &ResourceEntry->OperationalProps,
|
|
GenJobResourcePrivateProperties );
|
|
|
|
//
|
|
// If the resource is online, return a non-success status.
|
|
//
|
|
if (status == ERROR_SUCCESS) {
|
|
if ( ResourceEntry->Online ) {
|
|
status = ERROR_RESOURCE_PROPERTIES_STORED;
|
|
} else {
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
|
|
} // GenJobSetPrivateResProperties
|
|
|
|
#if LOADBAL_SUPPORT
|
|
DWORD
|
|
GenJobGetPids(
|
|
IN OUT PGENJOB_RESOURCE ResourceEntry,
|
|
OUT PVOID OutBuffer,
|
|
IN DWORD OutBufferSize,
|
|
OUT LPDWORD BytesReturned
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get array of PIDs (as DWORDS) to return for load balancing purposes.
|
|
|
|
Arguments:
|
|
|
|
ResourceEntry - Supplies the resource entry on which to operate.
|
|
|
|
OutBuffer - Supplies a pointer to a buffer for output data.
|
|
|
|
OutBufferSize - Supplies the size, in bytes, of the buffer pointed
|
|
to by OutBuffer.
|
|
|
|
BytesReturned - The number of bytes returned in OutBuffer.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
|
|
A Win32 error code on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
CLUSPROP_BUFFER_HELPER props;
|
|
|
|
props.pb = OutBuffer;
|
|
*BytesReturned = sizeof(*props.pdw);
|
|
|
|
if ( OutBufferSize < sizeof(*props.pdw) ) {
|
|
return(ERROR_MORE_DATA);
|
|
}
|
|
|
|
*(props.pdw) = ResourceEntry->ProcessId;
|
|
|
|
return(ERROR_SUCCESS);
|
|
|
|
} // GenJobGetPids
|
|
#endif
|
|
|
|
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.
|
|
|
|
remove when moving to clusres
|
|
|
|
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.
|
|
|
|
SetResourceStatus - xxx
|
|
|
|
LogEvent - xxx
|
|
|
|
FunctionTable - Returns the Function Table for this resource type.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
|
|
A Win32 error code on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( (MinVersionSupported > CLRES_VERSION_V1_00) ||
|
|
(MaxVersionSupported < CLRES_VERSION_V1_00) ) {
|
|
return(ERROR_REVISION_MISMATCH);
|
|
}
|
|
|
|
if ( !ClusResLogEvent ) {
|
|
ClusResLogEvent = LogEvent;
|
|
ClusResSetResourceStatus = SetResourceStatus;
|
|
}
|
|
|
|
if ( lstrcmpiW( ResourceType, CLUS_RESTYPE_NAME_GENJOB ) == 0 ) {
|
|
*FunctionTable = &GenJobFunctionTable;
|
|
return(ERROR_SUCCESS);
|
|
} else {
|
|
return(ERROR_CLUSTER_RESNAME_NOT_FOUND);
|
|
}
|
|
} // Startup
|
|
|
|
//***********************************************************
|
|
//
|
|
// Define Function Table
|
|
//
|
|
//***********************************************************
|
|
|
|
CLRES_V1_FUNCTION_TABLE( GenJobFunctionTable, // Name
|
|
CLRES_VERSION_V1_00, // Version
|
|
GenJob, // Prefix
|
|
NULL, // Arbitrate
|
|
NULL, // Release
|
|
GenJobResourceControl,// ResControl
|
|
GenJobResourceTypeControl ); // ResTypeControl
|