Source code of Windows XP (NT5)
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.

776 lines
16 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. job.c
  5. Abstract:
  6. A user mode app that allows creation and management of jobs.
  7. Environment:
  8. User mode only
  9. Revision History:
  10. 03-26-96 : Created
  11. --*/
  12. //
  13. // this module may be compiled at warning level 4 with the following
  14. // warnings disabled:
  15. //
  16. #pragma warning(disable:4200) // array[0]
  17. #pragma warning(disable:4201) // nameless struct/unions
  18. #pragma warning(disable:4214) // bit fields other than int
  19. #include <string.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <tchar.h>
  23. #include <assert.h>
  24. #include <windows.h>
  25. #include <devioctl.h>
  26. #include "jobmgr.h"
  27. void PrintHelp(char *Command);
  28. DWORD TestCommand(PCOMMAND commandEntry, int argc, char *argv[]);
  29. DWORD HelpCommand(PCOMMAND commandEntry, int argc, char *argv[]);
  30. DWORD CreateJobCommand(PCOMMAND commandEntry, int argc, char *argv[]);
  31. DWORD KillJobCommand(PCOMMAND commandEntry, int argc, char *argv[]);
  32. DWORD ExecuteCommand(PCOMMAND commandEntry, int argc, char *argv[]);
  33. DWORD QueryJobCommand(PCOMMAND commandEntry, int argc, char *argv[]);
  34. DWORD AssignProcessCommand(PCOMMAND commandEntry, int argc, char *argv[]);
  35. DWORD SetPriorityCommand(PCOMMAND CommandEntry,int argc, char *argv[]);
  36. //
  37. // List of commands
  38. // all command names are case sensitive
  39. // arguments are passed into command routines
  40. // list must be terminated with NULL command
  41. // command will not be listed in help if description == NULL
  42. //
  43. COMMAND CommandArray[] = {
  44. {"create",
  45. "creates the specified job object",
  46. "jobmgr create [-h] <job name> [process name [args ...]]\n"
  47. " Creates a job object with the specified name.\n"
  48. " -h - jobmgr will sleep after creating the job object until cancelled.\n"
  49. " <job name> - specifies the job name.\n",
  50. CreateJobCommand
  51. },
  52. {"exec",
  53. "executes a program in the specified job object",
  54. "jobmgr exec <job name> <command> [args ...]\n"
  55. " Executes the command in the specified job.\n"
  56. " <command> - [quoted] string specifying the command any any arguments.\n",
  57. ExecuteCommand
  58. },
  59. {"help",
  60. "help for all commands",
  61. "jobmgr help [command]\n"
  62. " Lists help for specified command or all commands.\n",
  63. HelpCommand},
  64. {"assign",
  65. "assigns a process to the specified job",
  66. "jobmgr assign <job name> <process id>\n"
  67. " Associates the process with the specified job.\n",
  68. AssignProcessCommand
  69. },
  70. {"kill",
  71. "kills a job object and associated processes",
  72. "kill <job name>\n",
  73. KillJobCommand},
  74. {"query",
  75. "queries information about a job object",
  76. "query [-alpsu | -*] <job name>\n"
  77. " a - dump accounting (basic & io) information\n"
  78. " l - dump limit (basic & extended) information\n"
  79. " p - dump process ID list\n"
  80. " s - dump security limit information\n"
  81. " u - dump UI restrictions\n"
  82. " * - dump all information (cannot be specified with other options)\n"
  83. " if no options are specified the process ID list will be dumped\n.",
  84. QueryJobCommand},
  85. {"setpriority",
  86. "Sets priority for processes within the job 0 - 5. 0 = Idle, 5 = Realtime, 2 = Normal.",
  87. "setpriority <job name> <priority>\n",
  88. SetPriorityCommand},
  89. {"test",
  90. NULL,
  91. "jobmgr test [arg]...\n",
  92. TestCommand},
  93. {NULL, NULL, NULL}
  94. };
  95. int __cdecl main(int argc, char *argv[])
  96. {
  97. int i = 0;
  98. char buffer[32];
  99. if(argc < 2) {
  100. printf("Usage: jobmgr <command> [parameters]\n");
  101. printf("possible commands: \n");
  102. HelpCommand(NULL, argc - 1 , argv + 1);
  103. printf("\n");
  104. return -1;
  105. }
  106. //
  107. // Iterate through the command array and find the correct function to
  108. // call.
  109. //
  110. while(CommandArray[i].Name != NULL) {
  111. if(strcmp(argv[1], CommandArray[i].Name) == 0) {
  112. DWORD status;
  113. status = (CommandArray[i].Function)(&(CommandArray[i]),
  114. (argc - 2),
  115. &(argv[2]));
  116. if(status == -1) {
  117. PrintHelp(CommandArray[i].Name);
  118. return -1;
  119. } else if(status != 0) {
  120. DWORD length;
  121. PVOID buffer;
  122. printf("Error: command %s returned status %d\n",
  123. CommandArray[i].Name, status);
  124. length = FormatMessage((FORMAT_MESSAGE_ALLOCATE_BUFFER |
  125. FORMAT_MESSAGE_FROM_SYSTEM |
  126. FORMAT_MESSAGE_IGNORE_INSERTS |
  127. (FORMAT_MESSAGE_MAX_WIDTH_MASK & 0)),
  128. NULL,
  129. status,
  130. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  131. (LPTSTR) &buffer,
  132. 1,
  133. NULL);
  134. if(length != 0) {
  135. printf("%s", buffer);
  136. }
  137. }
  138. break;
  139. }
  140. i++;
  141. }
  142. if(CommandArray[i].Name == NULL) {
  143. printf("Unknown command %s\n", argv[2]);
  144. }
  145. return 0;
  146. }
  147. VOID
  148. PrintBuffer(
  149. IN PUCHAR Buffer,
  150. IN SIZE_T Size
  151. )
  152. {
  153. DWORD offset = 0;
  154. while (Size > 0x10) {
  155. printf( "%08x:"
  156. " %02x %02x %02x %02x %02x %02x %02x %02x"
  157. " %02x %02x %02x %02x %02x %02x %02x %02x"
  158. "\n",
  159. offset,
  160. *(Buffer + 0), *(Buffer + 1), *(Buffer + 2), *(Buffer + 3),
  161. *(Buffer + 4), *(Buffer + 5), *(Buffer + 6), *(Buffer + 7),
  162. *(Buffer + 8), *(Buffer + 9), *(Buffer + 10), *(Buffer + 11),
  163. *(Buffer + 12), *(Buffer + 13), *(Buffer + 14), *(Buffer + 15)
  164. );
  165. Size -= 0x10;
  166. offset += 0x10;
  167. Buffer += 0x10;
  168. }
  169. if (Size != 0) {
  170. DWORD spaceIt;
  171. printf("%08x:", offset);
  172. for (spaceIt = 0; Size != 0; Size--) {
  173. if ((spaceIt%8)==0) {
  174. printf(" "); // extra space every eight chars
  175. }
  176. printf(" %02x", *Buffer);
  177. spaceIt++;
  178. Buffer++;
  179. }
  180. printf("\n");
  181. }
  182. return;
  183. }
  184. DWORD TestCommand(PCOMMAND commandEntry, int argc, char *argv[])
  185. /*++
  186. Routine Description:
  187. Tests the command "parsing"
  188. Arguments:
  189. device - a file handle to send the ioctl to
  190. argc - the number of additional arguments. should be zero
  191. argv - the additional arguments
  192. Return Value:
  193. STATUS_SUCCESS if successful
  194. The value of GetLastError() from the point of failure
  195. --*/
  196. {
  197. int i;
  198. DWORD result = ERROR_SUCCESS;
  199. printf("Test - %d additional arguments\n", argc);
  200. for(i = 0; i < argc; i++) {
  201. printf("arg %d: %s\n", i, argv[i]);
  202. }
  203. if(argc >= 1) {
  204. result = atoi(argv[0]);
  205. }
  206. printf("returning %d\n", result);
  207. return result;
  208. }
  209. void PrintHelp(char *Command)
  210. /*++
  211. Routine Description:
  212. Prints detailed help for a particular command.
  213. Arguments:
  214. device - unused
  215. argc - unused
  216. argv - unused
  217. Return Value:
  218. STATUS_SUCCESS
  219. --*/
  220. {
  221. int i;
  222. assert(Command != NULL);
  223. for(i = 0; CommandArray[i].Name != NULL; i++) {
  224. COMMAND *entry;
  225. entry = &(CommandArray[i]);
  226. if(_stricmp(entry->Name, Command) == 0) {
  227. if(entry->ExtendedHelp != NULL) {
  228. printf("%s", entry->ExtendedHelp);
  229. } else {
  230. printf(" %s - %s\n", entry->Name, entry->Description);
  231. }
  232. return;
  233. }
  234. }
  235. printf("Command %s not recognized\n", Command);
  236. return;
  237. }
  238. DWORD HelpCommand(PCOMMAND commandEntry, int argc, char *argv[])
  239. /*++
  240. Routine Description:
  241. Prints out the command list
  242. Arguments:
  243. device - unused
  244. argc - unused
  245. argv - unused
  246. Return Value:
  247. STATUS_SUCCESS
  248. --*/
  249. {
  250. int i = 0;
  251. if(argc >= 1) {
  252. PrintHelp(argv[0]);
  253. } else for(i = 0; CommandArray[i].Name != NULL; i++) {
  254. COMMAND *entry;
  255. entry = &(CommandArray[i]);
  256. if(entry->Description != NULL) {
  257. printf(" %s - %s\n", entry->Name, entry->Description);
  258. }
  259. }
  260. return ERROR_SUCCESS;
  261. }
  262. DWORD CreateJobCommand(PCOMMAND CommandEntry, int argc, char *argv[])
  263. /*++
  264. Routine Description:
  265. Prints out the command list
  266. Arguments:
  267. device - unused
  268. argc - unused
  269. argv - unused
  270. Return Value:
  271. STATUS_SUCCESS
  272. --*/
  273. {
  274. BOOL sleep = FALSE;
  275. LPCTSTR jobName;
  276. HANDLE job;
  277. //
  278. // Get the name of the job object from the arguments.
  279. //
  280. if(argc == 0) {
  281. PrintHelp(CommandEntry->Name);
  282. return -1;
  283. } else if(argc == 1) {
  284. jobName = argv[0];
  285. } else {
  286. if((argv[0][0] == '-') && (tolower(argv[0][1] == 's'))) {
  287. sleep = TRUE;
  288. }
  289. jobName = argv[1];
  290. }
  291. printf("Creating job %s\n", jobName);
  292. job = CreateJobObject(NULL, jobName);
  293. if(job == NULL) {
  294. DWORD status = GetLastError();
  295. printf("Error %d occurred creating job\n", status);
  296. return status;
  297. }
  298. printf("Job object %s created\n", jobName);
  299. if(sleep) {
  300. printf("Sleeping...\n");
  301. SleepEx(INFINITE, TRUE);
  302. printf("process alerted - exiting\n");
  303. }
  304. //
  305. // Destroy the job object.
  306. //
  307. CloseHandle(job);
  308. return ERROR_SUCCESS;
  309. }
  310. ULONG PriorityTable[] = { IDLE_PRIORITY_CLASS,
  311. BELOW_NORMAL_PRIORITY_CLASS,
  312. NORMAL_PRIORITY_CLASS,
  313. ABOVE_NORMAL_PRIORITY_CLASS,
  314. HIGH_PRIORITY_CLASS,
  315. REALTIME_PRIORITY_CLASS };
  316. DWORD
  317. SetPriorityCommand(
  318. PCOMMAND CommandEntry,
  319. int argc,
  320. char *argv[]
  321. )
  322. {
  323. LPCTSTR jobName;
  324. int i;
  325. DWORD status;
  326. ULONG Priority;
  327. HANDLE Job;
  328. JOBOBJECT_BASIC_LIMIT_INFORMATION Limits;
  329. if(argc < 2) {
  330. return -1;
  331. }
  332. //
  333. // save the job name and push argc/argv forward.
  334. //
  335. jobName = argv[0];
  336. argv += 1;
  337. argc -= 1;
  338. Priority = atoi( argv[0]);
  339. if (Priority > 5) {
  340. printf("Priority must be 0 - 5\n");
  341. return ERROR_INVALID_PARAMETER;
  342. }
  343. //
  344. // Open a handle to the specified job object.
  345. //
  346. Job = OpenJobObject(JOB_OBJECT_SET_ATTRIBUTES , FALSE, jobName);
  347. if(Job == NULL) {
  348. return GetLastError();
  349. }
  350. //
  351. // And set the priority limit.
  352. //
  353. memset( &Limits, 0, sizeof( Limits));
  354. Limits.PriorityClass = PriorityTable[ Priority];
  355. Limits.LimitFlags = JOB_OBJECT_LIMIT_PRIORITY_CLASS;
  356. if (!SetInformationJobObject( Job,
  357. JobObjectBasicLimitInformation,
  358. (PVOID)&Limits,
  359. sizeof( Limits))) {
  360. return GetLastError();
  361. }
  362. CloseHandle(Job);
  363. return 0;
  364. }
  365. DWORD
  366. ExecuteCommand(
  367. PCOMMAND CommandEntry,
  368. int argc,
  369. char *argv[]
  370. )
  371. {
  372. LPCTSTR jobName;
  373. ULONG commandLineLength = 0;
  374. LPTSTR commandLine = NULL;
  375. LPTSTR tmp;
  376. SECURITY_ATTRIBUTES security;
  377. HANDLE job;
  378. STARTUPINFO startupInfo;
  379. PROCESS_INFORMATION processInfo;
  380. int i;
  381. DWORD status;
  382. if(argc < 2) {
  383. return -1;
  384. }
  385. //
  386. // save the job name and push argc/argv forward.
  387. //
  388. jobName = argv[0];
  389. argv += 1;
  390. argc -= 1;
  391. //
  392. // Create a command line to hand to CreateProcess. Start by counting the
  393. // number of bytes necessary for the buffer.
  394. //
  395. for(i = 0; i < argc; i++) {
  396. commandLineLength += _tcslen(argv[i]);
  397. commandLineLength += 1;
  398. if(_tcschr(argv[i], TEXT(' ')) != NULL) {
  399. commandLineLength += 2;
  400. }
  401. }
  402. commandLineLength += 1;
  403. commandLine = LocalAlloc(LPTR, commandLineLength * sizeof(TCHAR));
  404. if(commandLine == NULL) {
  405. status = GetLastError();
  406. return status;
  407. }
  408. //
  409. // Now copy each argument string into the buffer.
  410. //
  411. tmp = commandLine;
  412. for(i = 0; i < argc; i++) {
  413. ULONG size;
  414. BOOLEAN containsSpace;
  415. if(_tcschr(argv[i], TEXT(' ')) != NULL) {
  416. containsSpace = TRUE;
  417. *tmp = TEXT('\"');
  418. tmp += 1;
  419. } else {
  420. containsSpace = FALSE;
  421. }
  422. size = _tcslen(argv[i]);
  423. memcpy(tmp, argv[i], size);
  424. if(containsSpace) {
  425. tmp[size] = TEXT('\"');
  426. tmp += 1;
  427. }
  428. tmp[size] = TEXT(' ');
  429. tmp += size + 1;
  430. }
  431. printf("Command Arguments are %s\n", commandLine);
  432. //
  433. // Open a handle to the specified job object.
  434. //
  435. printf("Opening job %s\n", jobName);
  436. security.nLength = sizeof(SECURITY_ATTRIBUTES);
  437. security.lpSecurityDescriptor = NULL;
  438. security.bInheritHandle = TRUE;
  439. job = CreateJobObject(&security, jobName);
  440. if(job == NULL) {
  441. status = GetLastError();
  442. LocalFree(commandLine);
  443. return status;
  444. }
  445. printf("Creating process '%s'\n", commandLine);
  446. GetStartupInfo(&startupInfo);
  447. //
  448. // Create the process but leave it suspended so we can assign it to the
  449. // job we created before it starts running.
  450. //
  451. if(!CreateProcess(NULL,
  452. commandLine,
  453. NULL,
  454. NULL,
  455. TRUE,
  456. (CREATE_NEW_CONSOLE | CREATE_SUSPENDED),
  457. NULL,
  458. NULL,
  459. &startupInfo,
  460. &processInfo)) {
  461. status = GetLastError();
  462. CloseHandle(job);
  463. LocalFree(commandLine);
  464. return status;
  465. }
  466. //
  467. // Assign the process to the job.
  468. //
  469. printf("Assigning process %d to job %s\n",
  470. processInfo.dwProcessId, jobName);
  471. if(!AssignProcessToJobObject(job, processInfo.hProcess)) {
  472. status = GetLastError();
  473. TerminateProcess(processInfo.hProcess, ERROR_SUCCESS);
  474. CloseHandle(processInfo.hProcess);
  475. CloseHandle(processInfo.hThread);
  476. CloseHandle(job);
  477. LocalFree(commandLine);
  478. return status;
  479. }
  480. //
  481. // Unsuspend the process.
  482. //
  483. if(ResumeThread(processInfo.hThread) == -1) {
  484. status = GetLastError();
  485. TerminateProcess(processInfo.hProcess, ERROR_SUCCESS);
  486. CloseHandle(processInfo.hProcess);
  487. CloseHandle(processInfo.hThread);
  488. CloseHandle(job);
  489. LocalFree(commandLine);
  490. return status;
  491. }
  492. //
  493. // Close all our handles.
  494. //
  495. CloseHandle(processInfo.hProcess);
  496. CloseHandle(processInfo.hThread);
  497. CloseHandle(job);
  498. LocalFree(commandLine);
  499. return ERROR_SUCCESS;
  500. }
  501. DWORD
  502. KillJobCommand(
  503. IN PCOMMAND CommandEntry,
  504. IN int argc,
  505. IN char* argv[]
  506. )
  507. {
  508. HANDLE job;
  509. DWORD status;
  510. if(argc == 0) {
  511. return -1;
  512. }
  513. job = OpenJobObject(JOB_OBJECT_TERMINATE, FALSE, argv[0]);
  514. if(job == NULL) {
  515. return GetLastError();
  516. }
  517. TerminateJobObject(job, ERROR_PROCESS_ABORTED);
  518. status = GetLastError();
  519. CloseHandle(job);
  520. return status;
  521. }
  522. DWORD
  523. AssignProcessCommand(
  524. IN PCOMMAND CommandEntry,
  525. IN int argc,
  526. IN char* argv[]
  527. )
  528. {
  529. HANDLE job;
  530. DWORD processId;
  531. HANDLE process;
  532. DWORD status = ERROR_SUCCESS;
  533. if(argc != 2) {
  534. return -1;
  535. }
  536. processId = _tcstoul(argv[1], NULL, 10);
  537. printf("process id %s = %d\n", argv[1], processId);
  538. if(processId == 0) {
  539. printf("Invalid process id %s\n", argv[1]);
  540. return -1;
  541. }
  542. //
  543. // Open the job first.
  544. //
  545. job = OpenJobObject(JOB_OBJECT_ASSIGN_PROCESS, FALSE, argv[0]);
  546. if(job == NULL) {
  547. return GetLastError();
  548. }
  549. //
  550. // Open the process now.
  551. //
  552. process = OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE,
  553. FALSE,
  554. processId);
  555. if(process == NULL) {
  556. status = GetLastError();
  557. CloseHandle(job);
  558. return status;
  559. }
  560. //
  561. // Assign the process to the job.
  562. //
  563. if(!AssignProcessToJobObject(job, process)) {
  564. status = GetLastError();
  565. }
  566. CloseHandle(job);
  567. CloseHandle(process);
  568. return status;
  569. }