windows-nt/Source/XPSP1/NT/sdktools/job/query.c

612 lines
18 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
job.c
Abstract:
A user mode app that allows creation and management of jobs.
Environment:
User mode only
Revision History:
03-26-96 : Created
--*/
//
// this module may be compiled at warning level 4 with the following
// warnings disabled:
//
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <assert.h>
#include <windows.h>
#include <devioctl.h>
#include "jobmgr.h"
typedef struct {
char Option;
JOBOBJECTINFOCLASS InfoClass;
char *Name;
DWORD (*Function)(HANDLE Job, JOBOBJECTINFOCLASS InfoClass);
} JOB_QUERY_OPTION, *PJOB_QUERY_OPTION;
#define MKOPTION(optChar, optClass) {optChar, optClass, #optClass, Dump##optClass}
DWORD DumpJobObjectBasicProcessIdList(HANDLE JobHandle,
JOBOBJECTINFOCLASS InfoClass);
DWORD DumpJobObjectBasicUIRestrictions(HANDLE JobHandle,
JOBOBJECTINFOCLASS InfoClass);
DWORD
DumpJobObjectBasicAndIoAccountingInformation(
HANDLE JobHandle,
JOBOBJECTINFOCLASS InfoClass
);
DWORD
DumpJobObjectExtendedLimitInformation(
HANDLE Job,
JOBOBJECTINFOCLASS InfoClass
);
DWORD
DumpJobObjectSecurityLimitInformation(
HANDLE JobHandle,
JOBOBJECTINFOCLASS InfoClass
);
JOB_QUERY_OPTION JobInfoClasses[] = {
MKOPTION('a', JobObjectBasicAndIoAccountingInformation),
MKOPTION('l', JobObjectExtendedLimitInformation),
MKOPTION('p', JobObjectBasicProcessIdList),
MKOPTION('s', JobObjectSecurityLimitInformation),
MKOPTION('u', JobObjectBasicUIRestrictions),
{'\0', 0, NULL}
};
DWORD
QueryJobCommand(
IN PCOMMAND CommandEntry,
IN int argc,
IN char* argv[]
)
{
TCHAR defaultOptions[] = {TEXT('p'), TEXT('\0')};
PTSTR options;
PTSTR jobName;
HANDLE job;
int i;
BOOLEAN matchAll = FALSE;
DWORD status;
if(argc == 0) {
return -1;
}
GetAllProcessInfo();
if((argc > 1) && (argv[0][0] == '-')) {
// a - accounting & io
// l - extended limit info
// p - process id list
// u - basic ui restrictions
// s - security limits
options = &(argv[0][1]);
argc -= 1;
argv += 1;
} else {
options = defaultOptions;
}
if(_tcschr(options, TEXT('*')) != NULL) {
if(_tcslen(options) != 1) {
printf("Cannot specify '*' with other flags\n");
return -1;
} else {
matchAll = TRUE;
options = defaultOptions;
}
}
jobName = argv[0];
_tprintf("Opening job object %s\n", jobName);
job = OpenJobObject(JOB_OBJECT_QUERY, FALSE, jobName);
if(job == NULL) {
return GetLastError();
}
for(i = 0; JobInfoClasses[i].Option != '\0'; i++) {
LPTSTR match;
if(!matchAll) {
match = _tcschr(options, JobInfoClasses[i].Option);
if(match == NULL) {
continue;
}
//
// Clear the option so we can report the invalid option flags at the
// end.
//
*match = ' ';
}
_tprintf("%s [%#x]:\n", JobInfoClasses[i].Name,
JobInfoClasses[i].InfoClass);
status = JobInfoClasses[i].Function(job,
JobInfoClasses[i].InfoClass);
_tprintf("\n");
if(status != ERROR_SUCCESS) {
DWORD length;
PVOID buffer;
_tprintf("Error %s querying info: ",
CommandArray[i].Name, status);
length = FormatMessage((FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
(FORMAT_MESSAGE_MAX_WIDTH_MASK & 0)),
NULL,
status,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &buffer,
1,
NULL);
if(length != 0) {
_tprintf("%s", buffer);
LocalFree(buffer);
}
}
}
if(!matchAll) {
LPSTR header = "Option flag not understood:";
while(options[0] != TEXT('\0')) {
if(options[0] != TEXT(' ')) {
_tprintf("%s %c", header, options[0]);
header = "";
}
options += 1;
}
}
#if 0
for(;options[0] != '\0'; options += 1) {
int i;
for(i = 0; JobInfoClasses[i].Option != '\0'; i++) {
if((options[0] != TEXT('*')) &&
(JobInfoClasses[i].Option != tolower(options[0]))) {
continue;
}
_tprintf("%s [%#x]:\n", JobInfoClasses[i].Name,
JobInfoClasses[i].InfoClass);
status = JobInfoClasses[i].Function(job,
JobInfoClasses[i].InfoClass);
_tprintf("\n");
if(status != ERROR_SUCCESS) {
DWORD length;
PVOID buffer;
_tprintf("Error %s querying info: ",
CommandArray[i].Name, status);
length = FormatMessage((FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
(FORMAT_MESSAGE_MAX_WIDTH_MASK & 0)),
NULL,
status,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &buffer,
1,
NULL);
if(length != 0) {
_tprintf("%s", buffer);
LocalFree(buffer);
}
}
break;
}
if(JobInfoClasses[i].Option == '\0') {
_tprintf("invalid option flag '%c'\n", options[0]);
}
}
#endif
CloseHandle(job);
return ERROR_SUCCESS;
}
DWORD
DumpJobObjectBasicProcessIdList(
HANDLE Job,
JOBOBJECTINFOCLASS InfoClass
)
{
JOBOBJECT_BASIC_PROCESS_ID_LIST buffer;
PJOBOBJECT_BASIC_PROCESS_ID_LIST idList = NULL;
ULONG bufferSize;
BOOL result;
DWORD status;
DWORD i;
result = QueryInformationJobObject(Job,
InfoClass,
&buffer,
sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST),
NULL);
status = GetLastError();
if((!result) && (status != ERROR_MORE_DATA)) {
return status;
}
do {
if(idList != NULL) {
buffer.NumberOfAssignedProcesses =
idList->NumberOfAssignedProcesses;
LocalFree(idList);
idList = NULL;
}
//
// Calculate the actual size of the list and allocate a buffer to hold it.
//
bufferSize = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST);
bufferSize -= sizeof(ULONG_PTR);
bufferSize += sizeof(ULONG_PTR) * buffer.NumberOfAssignedProcesses;
assert(idList == NULL);
idList = LocalAlloc(LPTR, bufferSize);
if(idList == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
result = QueryInformationJobObject(Job,
InfoClass,
idList,
bufferSize,
NULL);
status = GetLastError();
if((!result) && (status != ERROR_MORE_DATA)) {
LocalFree(idList);
return status;
}
} while(idList->NumberOfAssignedProcesses >
idList->NumberOfProcessIdsInList);
assert(idList->NumberOfAssignedProcesses ==
idList->NumberOfProcessIdsInList);
//
// Dump the information.
//
_tprintf(" %d processes assigned to job:\n",
idList->NumberOfAssignedProcesses);
for(i = 0; i < idList->NumberOfAssignedProcesses; i++) {
_tprintf("%8d", idList->ProcessIdList[i]);
PrintProcessInfo(idList->ProcessIdList[i]);
_tprintf("\n");
}
LocalFree(idList);
return ERROR_SUCCESS;
}
DWORD
DumpJobObjectBasicUIRestrictions(
HANDLE Job,
JOBOBJECTINFOCLASS InfoClass
)
{
JOBOBJECT_BASIC_UI_RESTRICTIONS uiLimit;
static FLAG_NAME jobUiLimitFlags[] = {
FLAG_NAME(JOB_OBJECT_UILIMIT_HANDLES ), //0x00000001
FLAG_NAME(JOB_OBJECT_UILIMIT_READCLIPBOARD ), //0x00000002
FLAG_NAME(JOB_OBJECT_UILIMIT_WRITECLIPBOARD ), //0x00000004
FLAG_NAME(JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS ), //0x00000008
FLAG_NAME(JOB_OBJECT_UILIMIT_DISPLAYSETTINGS ), //0x00000010
FLAG_NAME(JOB_OBJECT_UILIMIT_GLOBALATOMS ), //0x00000020
FLAG_NAME(JOB_OBJECT_UILIMIT_DESKTOP ), //0x00000040
FLAG_NAME(JOB_OBJECT_UILIMIT_EXITWINDOWS ), //0x00000080
{0,0}
};
BOOL result;
DWORD status;
DWORD i;
result = QueryInformationJobObject(Job,
InfoClass,
&uiLimit,
sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS),
NULL);
status = GetLastError();
if(!result) {
return status;
}
if(uiLimit.UIRestrictionsClass == JOB_OBJECT_UILIMIT_NONE) {
_tprintf(" Job has no UI restrictions\n");
return ERROR_SUCCESS;
}
DumpFlags(2,
"UI Restrictions",
uiLimit.UIRestrictionsClass,
jobUiLimitFlags);
return ERROR_SUCCESS;
}
DWORD
DumpJobObjectBasicAndIoAccountingInformation(
HANDLE Job,
JOBOBJECTINFOCLASS InfoClass
)
{
JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION info;
BOOL result;
DWORD status;
DWORD i;
result = QueryInformationJobObject(Job,
InfoClass,
&info,
sizeof(info),
NULL);
status = GetLastError();
if(!result) {
return status;
}
xprintf(2, "Basic Info\n");
xprintf(4, "TotalUserTime: %s\n", TicksToString(info.BasicInfo.TotalUserTime));
xprintf(4, "TotalKernelTime: %s\n", TicksToString(info.BasicInfo.TotalKernelTime));
xprintf(4, "ThisPeriodTotalUserTime: %s\n", TicksToString(info.BasicInfo.ThisPeriodTotalUserTime));
xprintf(4, "ThisPeriodTotalKernelTime: %s\n", TicksToString(info.BasicInfo.ThisPeriodTotalKernelTime));
xprintf(4, "TotalPageFaultCount: %d\n", info.BasicInfo.TotalPageFaultCount);
xprintf(4, "TotalProcesses: %d\n", info.BasicInfo.TotalProcesses);
xprintf(4, "ActiveProcesses: %d\n", info.BasicInfo.ActiveProcesses);
xprintf(4, "TotalTerminatedProcesses: %d\n", info.BasicInfo.TotalTerminatedProcesses);
xprintf(2, "I/O Info\n");
xprintf(4, "ReadOperationCount: %I64d\n", info.IoInfo.ReadOperationCount);
xprintf(4, "WriteOperationCount: %I64d\n", info.IoInfo.WriteOperationCount);
xprintf(4, "OtherOperationCount: %I64d\n", info.IoInfo.OtherOperationCount);
xprintf(4, "ReadTransferCount: %I64d\n", info.IoInfo.ReadTransferCount);
xprintf(4, "WriteTransferCount: %I64d\n", info.IoInfo.WriteTransferCount);
xprintf(4, "OtherTransferCount: %I64d\n", info.IoInfo.OtherTransferCount);
return ERROR_SUCCESS;
}
DWORD
DumpJobObjectExtendedLimitInformation(
HANDLE Job,
JOBOBJECTINFOCLASS InfoClass
)
{
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
ULONG limits;
static FLAG_NAME basicJobLimitFlags[] = {
FLAG_NAME(JOB_OBJECT_LIMIT_WORKINGSET ), //0x00000001
FLAG_NAME(JOB_OBJECT_LIMIT_PROCESS_TIME ), //0x00000002
FLAG_NAME(JOB_OBJECT_LIMIT_JOB_TIME ), //0x00000004
FLAG_NAME(JOB_OBJECT_LIMIT_ACTIVE_PROCESS ), //0x00000008
FLAG_NAME(JOB_OBJECT_LIMIT_AFFINITY ), //0x00000010
FLAG_NAME(JOB_OBJECT_LIMIT_PRIORITY_CLASS ), //0x00000020
FLAG_NAME(JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME ), //0x00000040
FLAG_NAME(JOB_OBJECT_LIMIT_SCHEDULING_CLASS ), //0x00000080
{0,0}
};
//
// Extended Limits
//
static FLAG_NAME extendedJobLimitFlags[] = {
FLAG_NAME(JOB_OBJECT_LIMIT_PROCESS_MEMORY ), //0x00000100
FLAG_NAME(JOB_OBJECT_LIMIT_JOB_MEMORY ), //0x00000200
FLAG_NAME(JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION ), //0x00000400
FLAG_NAME(JOB_OBJECT_LIMIT_BREAKAWAY_OK ), //0x00000800
FLAG_NAME(JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK ), //0x00001000
FLAG_NAME(JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE ), //0x00002000
FLAG_NAME(JOB_OBJECT_LIMIT_RESERVED2 ), //0x00004000
FLAG_NAME(JOB_OBJECT_LIMIT_RESERVED3 ), //0x00008000
FLAG_NAME(JOB_OBJECT_LIMIT_RESERVED4 ), //0x00010000
FLAG_NAME(JOB_OBJECT_LIMIT_RESERVED5 ), //0x00020000
FLAG_NAME(JOB_OBJECT_LIMIT_RESERVED6 ), //0x00040000
{0,0}
};
BOOL result;
DWORD status;
DWORD i;
result = QueryInformationJobObject(Job,
InfoClass,
&info,
sizeof(info),
NULL);
status = GetLastError();
if(!result) {
return status;
}
limits = info.BasicLimitInformation.LimitFlags;
if(TEST_FLAG(limits, JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS) == 0) {
xprintf(2, "No basic limits on job\n");
} else {
DumpFlags(2, "Basic Limit Flags", limits & JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS, basicJobLimitFlags);
if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_PROCESS_TIME)) {
xprintf(4, "PerProcessUserTimeLimit: %s\n", TicksToString(info.BasicLimitInformation.PerProcessUserTimeLimit));
}
if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_JOB_TIME)) {
xprintf(4, "PerJobUserTimeLimit: %s\n", TicksToString(info.BasicLimitInformation.PerJobUserTimeLimit));
}
if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_WORKINGSET)) {
xprintf(4, "MinimumWorkingSetSize: %I64d\n", (ULONGLONG) info.BasicLimitInformation.MinimumWorkingSetSize);
xprintf(4, "MaximumWorkingSetSize: %I64d\n", (ULONGLONG) info.BasicLimitInformation.MaximumWorkingSetSize);
}
if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_ACTIVE_PROCESS)) {
xprintf(4, "ActiveProcessLimit: %d\n",info.BasicLimitInformation.ActiveProcessLimit);
}
if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_AFFINITY)) {
xprintf(4, "Affinity: %#I64x\n", (ULONGLONG)info.BasicLimitInformation.Affinity);
}
if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_PRIORITY_CLASS)) {
xprintf(4, "PriorityClass: %d\n",info.BasicLimitInformation.PriorityClass);
}
if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_SCHEDULING_CLASS)) {
xprintf(4, "SchedulingClass: %d\n",info.BasicLimitInformation.SchedulingClass);
}
}
if(TEST_FLAG(limits, JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS) == 0) {
xprintf(2, "No extended limits on job\n");
} else {
DumpFlags(2, "Extended Limit Flags", limits & JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS & ~JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS, extendedJobLimitFlags);
if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_PROCESS_MEMORY)) {
xprintf(4, "ProcessMemoryLimit: %I64d\n", (ULONGLONG) info.ProcessMemoryLimit);
}
if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_PROCESS_MEMORY)) {
xprintf(4, "JobMemoryLimit: %I64d\n", (ULONGLONG) info.JobMemoryLimit);
}
}
xprintf(2, "PeakProcessMemoryUsed: %I64d\n", (ULONGLONG) info.PeakProcessMemoryUsed);
xprintf(2, "PeakJobMemoryUsed: %I64d\n", (ULONGLONG) info.PeakJobMemoryUsed);
return ERROR_SUCCESS;
}
DWORD
DumpJobObjectSecurityLimitInformation(
HANDLE Job,
JOBOBJECTINFOCLASS InfoClass
)
{
JOBOBJECT_SECURITY_LIMIT_INFORMATION buffer;
PJOBOBJECT_SECURITY_LIMIT_INFORMATION info = NULL;
static FLAG_NAME jobSecurityLimitFlags[] = {
FLAG_NAME(JOB_OBJECT_SECURITY_NO_ADMIN ), //00000001
FLAG_NAME(JOB_OBJECT_SECURITY_RESTRICTED_TOKEN ), //00000002
FLAG_NAME(JOB_OBJECT_SECURITY_ONLY_TOKEN ), //00000004
FLAG_NAME(JOB_OBJECT_SECURITY_FILTER_TOKENS ), //00000008
{0, 0}
};
ULONG bufferSize;
BOOL result;
DWORD status;
DWORD i;
result = QueryInformationJobObject(Job,
InfoClass,
&buffer,
sizeof(buffer),
&bufferSize);
status = GetLastError();
if((!result) && (status != ERROR_MORE_DATA)) {
return status;
}
info = LocalAlloc(LPTR, bufferSize);
if(info == NULL) {
return GetLastError();
}
result = QueryInformationJobObject(Job, InfoClass, info, bufferSize, NULL);
if(!result) {
status = GetLastError();
LocalFree(info);
return status;
}
if(info->SecurityLimitFlags == 0) {
xprintf(2, "No security limitations on job\n");
} else {
DumpFlags(2, "SecurityLimitFlags", info->SecurityLimitFlags, jobSecurityLimitFlags);
}
LocalFree(info);
return ERROR_SUCCESS;
}