Leaked source code of windows server 2003
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

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