|
|
/*++
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; }
|