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.
775 lines
17 KiB
775 lines
17 KiB
/*++
|
|
|
|
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:
|
|
//
|
|
|
|
#pragma warning(disable:4200) // array[0]
|
|
#pragma warning(disable:4201) // nameless struct/unions
|
|
#pragma warning(disable:4214) // bit fields other than int
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <windows.h>
|
|
#include <devioctl.h>
|
|
|
|
#include "jobmgr.h"
|
|
|
|
void PrintHelp(char *Command);
|
|
|
|
DWORD TestCommand(PCOMMAND commandEntry, int argc, char *argv[]);
|
|
DWORD HelpCommand(PCOMMAND commandEntry, int argc, char *argv[]);
|
|
DWORD CreateJobCommand(PCOMMAND commandEntry, int argc, char *argv[]);
|
|
DWORD KillJobCommand(PCOMMAND commandEntry, int argc, char *argv[]);
|
|
DWORD ExecuteCommand(PCOMMAND commandEntry, int argc, char *argv[]);
|
|
DWORD QueryJobCommand(PCOMMAND commandEntry, int argc, char *argv[]);
|
|
DWORD AssignProcessCommand(PCOMMAND commandEntry, int argc, char *argv[]);
|
|
DWORD SetPriorityCommand(PCOMMAND CommandEntry,int argc, char *argv[]);
|
|
|
|
//
|
|
// List of commands
|
|
// all command names are case sensitive
|
|
// arguments are passed into command routines
|
|
// list must be terminated with NULL command
|
|
// command will not be listed in help if description == NULL
|
|
//
|
|
|
|
COMMAND CommandArray[] = {
|
|
{"create",
|
|
"creates the specified job object",
|
|
"jobmgr create [-s] <job name>\n"
|
|
" Creates a job object with the specified name.\n"
|
|
" -s - jobmgr will sleep after creating the job object until cancelled.\n"
|
|
" <job name> - specifies the job name.\n",
|
|
CreateJobCommand
|
|
},
|
|
|
|
{"exec",
|
|
"executes a program in the specified job object",
|
|
"jobmgr exec <job name> <command> [args ...]\n"
|
|
" Executes the command in the specified job.\n"
|
|
" <command> - [quoted] string specifying the command any any arguments.\n",
|
|
ExecuteCommand
|
|
},
|
|
|
|
{"help",
|
|
"help for all commands",
|
|
"jobmgr help [command]\n"
|
|
" Lists help for specified command or all commands.\n",
|
|
HelpCommand},
|
|
|
|
{"assign",
|
|
"assigns a process to the specified job",
|
|
"jobmgr assign <job name> <process id>\n"
|
|
" Associates the process with the specified job.\n",
|
|
AssignProcessCommand
|
|
},
|
|
|
|
{"kill",
|
|
"kills a job object and associated processes",
|
|
"kill <job name>\n",
|
|
KillJobCommand},
|
|
|
|
{"query",
|
|
"queries information about a job object",
|
|
"query [-alpsu | -*] <job name>\n"
|
|
" a - dump accounting (basic & io) information\n"
|
|
" l - dump limit (basic & extended) information\n"
|
|
" p - dump process ID list\n"
|
|
" s - dump security limit information\n"
|
|
" u - dump UI restrictions\n"
|
|
" * - dump all information (cannot be specified with other options)\n"
|
|
" if no options are specified the process ID list will be dumped\n.",
|
|
QueryJobCommand},
|
|
|
|
{"setpriority",
|
|
"Sets priority for processes within the job 0 - 5. 0 = Idle, 5 = Realtime, 2 = Normal.",
|
|
"setpriority <job name> <priority>\n",
|
|
SetPriorityCommand},
|
|
|
|
{"test",
|
|
NULL,
|
|
"jobmgr test [arg]...\n",
|
|
TestCommand},
|
|
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
int __cdecl main(int argc, char *argv[])
|
|
{
|
|
int i = 0;
|
|
|
|
if(argc < 2) {
|
|
puts("Usage: jobmgr <command> [parameters]");
|
|
puts("possible commands: ");
|
|
HelpCommand(NULL, 0 , NULL);
|
|
puts("");
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Iterate through the command array and find the correct function to
|
|
// call.
|
|
//
|
|
|
|
while(CommandArray[i].Name != NULL) {
|
|
|
|
if(strcmp(argv[1], CommandArray[i].Name) == 0) {
|
|
DWORD status;
|
|
|
|
status = (CommandArray[i].Function)(&(CommandArray[i]),
|
|
(argc - 2),
|
|
&(argv[2]));
|
|
|
|
if(status == -1) {
|
|
PrintHelp(CommandArray[i].Name);
|
|
return -1;
|
|
} else if(status != 0) {
|
|
DWORD length;
|
|
PVOID buffer;
|
|
|
|
printf("Error: command %s returned status %d\n",
|
|
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) {
|
|
puts(buffer);
|
|
LocalFree(buffer);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
if(CommandArray[i].Name == NULL) {
|
|
printf("Unknown command %s\n", argv[2]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
VOID
|
|
PrintBuffer(
|
|
IN PUCHAR Buffer,
|
|
IN SIZE_T Size
|
|
)
|
|
{
|
|
DWORD offset = 0;
|
|
|
|
while (Size > 0x10) {
|
|
printf( "%08x:"
|
|
" %02x %02x %02x %02x %02x %02x %02x %02x"
|
|
" %02x %02x %02x %02x %02x %02x %02x %02x"
|
|
"\n",
|
|
offset,
|
|
*(Buffer + 0), *(Buffer + 1), *(Buffer + 2), *(Buffer + 3),
|
|
*(Buffer + 4), *(Buffer + 5), *(Buffer + 6), *(Buffer + 7),
|
|
*(Buffer + 8), *(Buffer + 9), *(Buffer + 10), *(Buffer + 11),
|
|
*(Buffer + 12), *(Buffer + 13), *(Buffer + 14), *(Buffer + 15)
|
|
);
|
|
Size -= 0x10;
|
|
offset += 0x10;
|
|
Buffer += 0x10;
|
|
}
|
|
|
|
if (Size != 0) {
|
|
|
|
DWORD spaceIt;
|
|
|
|
printf("%08x:", offset);
|
|
for (spaceIt = 0; Size != 0; Size--) {
|
|
|
|
if ((spaceIt%8)==0) {
|
|
printf(" "); // extra space every eight chars
|
|
}
|
|
printf(" %02x", *Buffer);
|
|
spaceIt++;
|
|
Buffer++;
|
|
}
|
|
printf("\n");
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
DWORD TestCommand(PCOMMAND commandEntry, int argc, char *argv[])
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Tests the command "parsing"
|
|
|
|
Arguments:
|
|
device - a file handle to send the ioctl to
|
|
|
|
argc - the number of additional arguments. should be zero
|
|
|
|
argv - the additional arguments
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
The value of GetLastError() from the point of failure
|
|
|
|
--*/
|
|
|
|
{
|
|
int i;
|
|
DWORD result = ERROR_SUCCESS;
|
|
|
|
printf("Test - %d additional arguments\n", argc);
|
|
|
|
for(i = 0; i < argc; i++) {
|
|
printf("arg %d: %s\n", i, argv[i]);
|
|
}
|
|
|
|
if(argc >= 1) {
|
|
result = atoi(argv[0]);
|
|
}
|
|
|
|
printf("returning %d\n", result);
|
|
|
|
return result;
|
|
}
|
|
|
|
void PrintHelp(char *Command)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints detailed help for a particular command.
|
|
|
|
Arguments:
|
|
device - unused
|
|
|
|
argc - unused
|
|
|
|
argv - unused
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
int i;
|
|
|
|
assert(Command != NULL);
|
|
|
|
for(i = 0; CommandArray[i].Name != NULL; i++) {
|
|
COMMAND *entry;
|
|
|
|
entry = &(CommandArray[i]);
|
|
|
|
if(_stricmp(entry->Name, Command) == 0) {
|
|
if(entry->ExtendedHelp != NULL) {
|
|
printf("%s", entry->ExtendedHelp);
|
|
} else {
|
|
printf(" %s - %s\n", entry->Name, entry->Description);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
printf("Command %s not recognized\n", Command);
|
|
|
|
return;
|
|
}
|
|
|
|
DWORD HelpCommand(PCOMMAND commandEntry, int argc, char *argv[])
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints out the command list
|
|
|
|
Arguments:
|
|
device - unused
|
|
|
|
argc - unused
|
|
|
|
argv - unused
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
int i = 0;
|
|
|
|
if(argc >= 1) {
|
|
|
|
PrintHelp(argv[0]);
|
|
|
|
} else for(i = 0; CommandArray[i].Name != NULL; i++) {
|
|
|
|
COMMAND *entry;
|
|
|
|
entry = &(CommandArray[i]);
|
|
|
|
if(entry->Description != NULL) {
|
|
printf(" %s - %s\n", entry->Name, entry->Description);
|
|
}
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
DWORD CreateJobCommand(PCOMMAND CommandEntry, int argc, char *argv[])
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints out the command list
|
|
|
|
Arguments:
|
|
device - unused
|
|
|
|
argc - unused
|
|
|
|
argv - unused
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL sleep = FALSE;
|
|
LPCTSTR jobName;
|
|
|
|
HANDLE job;
|
|
|
|
//
|
|
// Get the name of the job object from the arguments.
|
|
//
|
|
|
|
if(argc <= 0) {
|
|
return -1;
|
|
} else if(argc == 1) {
|
|
jobName = argv[0];
|
|
} else {
|
|
if((argv[0][0] == '-') && (tolower(argv[0][1] == 's'))) {
|
|
sleep = TRUE;
|
|
}
|
|
jobName = argv[1];
|
|
}
|
|
|
|
printf("Creating job %s\n", jobName);
|
|
|
|
job = CreateJobObject(NULL, jobName);
|
|
|
|
if(job == NULL) {
|
|
DWORD status = GetLastError();
|
|
|
|
printf("Error %d occurred creating job\n", status);
|
|
return status;
|
|
}
|
|
|
|
printf("Job object %s created\n", jobName);
|
|
|
|
if(sleep) {
|
|
puts("Sleeping...");
|
|
SleepEx(INFINITE, TRUE);
|
|
puts("process alerted - exiting");
|
|
}
|
|
|
|
//
|
|
// Destroy the job object.
|
|
//
|
|
|
|
CloseHandle(job);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
ULONG PriorityTable[] = { IDLE_PRIORITY_CLASS,
|
|
BELOW_NORMAL_PRIORITY_CLASS,
|
|
NORMAL_PRIORITY_CLASS,
|
|
ABOVE_NORMAL_PRIORITY_CLASS,
|
|
HIGH_PRIORITY_CLASS,
|
|
REALTIME_PRIORITY_CLASS };
|
|
|
|
DWORD
|
|
SetPriorityCommand(
|
|
PCOMMAND CommandEntry,
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
LPCTSTR jobName;
|
|
int i;
|
|
DWORD status;
|
|
ULONG Priority;
|
|
HANDLE Job;
|
|
|
|
JOBOBJECT_BASIC_LIMIT_INFORMATION Limits;
|
|
|
|
if(argc < 2) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// extract job name and priority.
|
|
//
|
|
|
|
jobName = argv[0];
|
|
Priority = atoi(argv[1]);
|
|
|
|
if (Priority > 5) {
|
|
printf("Priority must be 0 - 5\n");
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Open a handle to the specified job object.
|
|
//
|
|
|
|
Job = OpenJobObject(JOB_OBJECT_SET_ATTRIBUTES , FALSE, jobName);
|
|
|
|
if(Job == NULL) {
|
|
return GetLastError();
|
|
}
|
|
|
|
//
|
|
// And set the priority limit.
|
|
//
|
|
|
|
memset( &Limits, 0, sizeof( Limits));
|
|
|
|
Limits.PriorityClass = PriorityTable[Priority];
|
|
Limits.LimitFlags = JOB_OBJECT_LIMIT_PRIORITY_CLASS;
|
|
|
|
if (!SetInformationJobObject(Job,
|
|
JobObjectBasicLimitInformation,
|
|
(PVOID)&Limits,
|
|
sizeof(Limits))) {
|
|
CloseHandle(Job);
|
|
return GetLastError();
|
|
}
|
|
|
|
CloseHandle(Job);
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ExecuteCommand(
|
|
PCOMMAND CommandEntry,
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
LPCTSTR jobName;
|
|
|
|
ULONG commandLineLength = 0;
|
|
LPTSTR commandLine = NULL;
|
|
LPTSTR tmp;
|
|
|
|
SECURITY_ATTRIBUTES security;
|
|
HANDLE job;
|
|
|
|
STARTUPINFO startupInfo;
|
|
PROCESS_INFORMATION processInfo;
|
|
|
|
int i;
|
|
DWORD status;
|
|
|
|
if(argc < 2) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// save the job name and push argc/argv forward.
|
|
//
|
|
|
|
jobName = argv[0];
|
|
argv += 1;
|
|
argc -= 1;
|
|
|
|
//
|
|
// Create a command line to hand to CreateProcess. Start by counting the
|
|
// number of bytes necessary for the buffer.
|
|
//
|
|
|
|
for(i = 0; i < argc; i++) {
|
|
commandLineLength += strlen(argv[i]);
|
|
commandLineLength += 1;
|
|
|
|
//
|
|
// If there's a space in the argument then leave room for quotes
|
|
// around it.
|
|
//
|
|
|
|
if(strchr(argv[i], ' ') != NULL) {
|
|
commandLineLength += 2;
|
|
}
|
|
}
|
|
|
|
commandLineLength += 1;
|
|
|
|
commandLine = LocalAlloc(LPTR, commandLineLength * sizeof(char));
|
|
|
|
if(commandLine == NULL) {
|
|
status = GetLastError();
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Now copy each argument string into the buffer.
|
|
//
|
|
|
|
tmp = commandLine;
|
|
|
|
for(i = 0; i < argc; i++) {
|
|
ULONG size;
|
|
BOOLEAN containsSpace;
|
|
|
|
if(strchr(argv[i], ' ') != NULL) {
|
|
containsSpace = TRUE;
|
|
*tmp = '\"';
|
|
tmp += 1;
|
|
} else {
|
|
containsSpace = FALSE;
|
|
}
|
|
|
|
size = strlen(argv[i]);
|
|
memcpy(tmp, argv[i], size);
|
|
|
|
if(containsSpace) {
|
|
tmp[size] = '\"';
|
|
tmp += 1;
|
|
}
|
|
|
|
tmp[size] = ' ';
|
|
tmp += size + 1;
|
|
}
|
|
|
|
printf("Command Arguments are %s\n", commandLine);
|
|
|
|
//
|
|
// Open a handle to the specified job object.
|
|
//
|
|
|
|
printf("Opening job %s\n", jobName);
|
|
|
|
security.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
security.lpSecurityDescriptor = NULL;
|
|
security.bInheritHandle = TRUE;
|
|
|
|
job = CreateJobObject(&security, jobName);
|
|
|
|
if(job == NULL) {
|
|
status = GetLastError();
|
|
LocalFree(commandLine);
|
|
return status;
|
|
}
|
|
|
|
printf("Creating process '%s'\n", commandLine);
|
|
|
|
GetStartupInfo(&startupInfo);
|
|
|
|
//
|
|
// Create the process but leave it suspended so we can assign it to the
|
|
// job we created before it starts running.
|
|
//
|
|
|
|
if(!CreateProcess(NULL,
|
|
commandLine,
|
|
NULL,
|
|
NULL,
|
|
TRUE,
|
|
(CREATE_NEW_CONSOLE | CREATE_SUSPENDED),
|
|
NULL,
|
|
NULL,
|
|
&startupInfo,
|
|
&processInfo)) {
|
|
status = GetLastError();
|
|
CloseHandle(job);
|
|
LocalFree(commandLine);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Assign the process to the job.
|
|
//
|
|
|
|
printf("Assigning process %d to job %s\n",
|
|
processInfo.dwProcessId, jobName);
|
|
|
|
if(!AssignProcessToJobObject(job, processInfo.hProcess)) {
|
|
status = GetLastError();
|
|
|
|
TerminateProcess(processInfo.hProcess, ERROR_SUCCESS);
|
|
CloseHandle(processInfo.hProcess);
|
|
CloseHandle(processInfo.hThread);
|
|
CloseHandle(job);
|
|
LocalFree(commandLine);
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Unsuspend the process.
|
|
//
|
|
|
|
if(ResumeThread(processInfo.hThread) == -1) {
|
|
status = GetLastError();
|
|
|
|
TerminateProcess(processInfo.hProcess, ERROR_SUCCESS);
|
|
CloseHandle(processInfo.hProcess);
|
|
CloseHandle(processInfo.hThread);
|
|
CloseHandle(job);
|
|
LocalFree(commandLine);
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Close all our handles.
|
|
//
|
|
|
|
CloseHandle(processInfo.hProcess);
|
|
CloseHandle(processInfo.hThread);
|
|
CloseHandle(job);
|
|
LocalFree(commandLine);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
DWORD
|
|
KillJobCommand(
|
|
IN PCOMMAND CommandEntry,
|
|
IN int argc,
|
|
IN char* argv[]
|
|
)
|
|
{
|
|
HANDLE job;
|
|
DWORD status;
|
|
|
|
if(argc <= 0) {
|
|
return -1;
|
|
}
|
|
|
|
job = OpenJobObject(JOB_OBJECT_TERMINATE, FALSE, argv[0]);
|
|
|
|
if(job == NULL) {
|
|
return GetLastError();
|
|
}
|
|
|
|
TerminateJobObject(job, ERROR_PROCESS_ABORTED);
|
|
|
|
status = GetLastError();
|
|
|
|
CloseHandle(job);
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AssignProcessCommand(
|
|
IN PCOMMAND CommandEntry,
|
|
IN int argc,
|
|
IN char* argv[]
|
|
)
|
|
{
|
|
HANDLE job;
|
|
|
|
DWORD processId;
|
|
HANDLE process;
|
|
|
|
DWORD status = ERROR_SUCCESS;
|
|
|
|
if(argc != 2) {
|
|
return -1;
|
|
}
|
|
|
|
processId = strtoul(argv[1], NULL, 10);
|
|
|
|
printf("process id %s = %d\n", argv[1], processId);
|
|
|
|
if(processId == 0) {
|
|
printf("Invalid process id %s\n", argv[1]);
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Open the job first.
|
|
//
|
|
|
|
job = OpenJobObject(JOB_OBJECT_ASSIGN_PROCESS, FALSE, argv[0]);
|
|
|
|
if(job == NULL) {
|
|
return GetLastError();
|
|
}
|
|
|
|
//
|
|
// Open the process now.
|
|
//
|
|
|
|
process = OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE,
|
|
FALSE,
|
|
processId);
|
|
|
|
if(process == NULL) {
|
|
status = GetLastError();
|
|
CloseHandle(job);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Assign the process to the job.
|
|
//
|
|
|
|
if(!AssignProcessToJobObject(job, process)) {
|
|
status = GetLastError();
|
|
}
|
|
|
|
CloseHandle(job);
|
|
CloseHandle(process);
|
|
return status;
|
|
}
|