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.

565 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. #include <string.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <stddef.h>
  20. #include <assert.h>
  21. #include <windows.h>
  22. #include <devioctl.h>
  23. #include "jobmgr.h"
  24. typedef struct {
  25. char Option;
  26. JOBOBJECTINFOCLASS InfoClass;
  27. char *Name;
  28. DWORD (*Function)(HANDLE Job, JOBOBJECTINFOCLASS InfoClass);
  29. } JOB_QUERY_OPTION, *PJOB_QUERY_OPTION;
  30. #define MKOPTION(optChar, optClass) {optChar, optClass, #optClass, Dump##optClass}
  31. DWORD DumpJobObjectBasicProcessIdList(HANDLE JobHandle,
  32. JOBOBJECTINFOCLASS InfoClass);
  33. DWORD DumpJobObjectBasicUIRestrictions(HANDLE JobHandle,
  34. JOBOBJECTINFOCLASS InfoClass);
  35. DWORD
  36. DumpJobObjectBasicAndIoAccountingInformation(
  37. HANDLE JobHandle,
  38. JOBOBJECTINFOCLASS InfoClass
  39. );
  40. DWORD
  41. DumpJobObjectExtendedLimitInformation(
  42. HANDLE Job,
  43. JOBOBJECTINFOCLASS InfoClass
  44. );
  45. DWORD
  46. DumpJobObjectSecurityLimitInformation(
  47. HANDLE JobHandle,
  48. JOBOBJECTINFOCLASS InfoClass
  49. );
  50. JOB_QUERY_OPTION JobInfoClasses[] = {
  51. MKOPTION('a', JobObjectBasicAndIoAccountingInformation),
  52. MKOPTION('l', JobObjectExtendedLimitInformation),
  53. MKOPTION('p', JobObjectBasicProcessIdList),
  54. MKOPTION('s', JobObjectSecurityLimitInformation),
  55. MKOPTION('u', JobObjectBasicUIRestrictions),
  56. {'\0', 0, NULL}
  57. };
  58. DWORD
  59. QueryJobCommand(
  60. IN PCOMMAND CommandEntry,
  61. IN int argc,
  62. IN char* argv[]
  63. )
  64. {
  65. CHAR defaultOptions[] = {'p', '\0'};
  66. PTSTR options;
  67. PTSTR jobName;
  68. HANDLE job;
  69. int i;
  70. BOOLEAN matchAll = FALSE;
  71. DWORD status;
  72. if(argc == 0) {
  73. return -1;
  74. }
  75. GetAllProcessInfo();
  76. if((argc > 1) && (argv[0][0] == '-')) {
  77. // a - accounting & io
  78. // l - extended limit info
  79. // p - process id list
  80. // u - basic ui restrictions
  81. // s - security limits
  82. options = &(argv[0][1]);
  83. argc -= 1;
  84. argv += 1;
  85. } else {
  86. options = defaultOptions;
  87. }
  88. if(strchr(options, '*') != NULL) {
  89. if(strlen(options) != 1) {
  90. puts("Cannot specify '*' with other flags");
  91. return -1;
  92. } else {
  93. matchAll = TRUE;
  94. options = defaultOptions;
  95. }
  96. }
  97. jobName = argv[0];
  98. printf("Opening job object %s\n", jobName);
  99. job = OpenJobObject(JOB_OBJECT_QUERY, FALSE, jobName);
  100. if(job == NULL) {
  101. return GetLastError();
  102. }
  103. for(i = 0; JobInfoClasses[i].Option != '\0'; i++) {
  104. LPSTR match;
  105. if(!matchAll) {
  106. match = strchr(options, JobInfoClasses[i].Option);
  107. if(match == NULL) {
  108. continue;
  109. }
  110. //
  111. // Clear the option so we can report the invalid option flags at the
  112. // end.
  113. //
  114. *match = ' ';
  115. }
  116. printf("%s [%#x]:\n", JobInfoClasses[i].Name,
  117. JobInfoClasses[i].InfoClass);
  118. status = JobInfoClasses[i].Function(job,
  119. JobInfoClasses[i].InfoClass);
  120. puts("");
  121. if(status != ERROR_SUCCESS) {
  122. DWORD length;
  123. LPSTR buffer;
  124. printf("Error %d querying info: ", status);
  125. length = FormatMessage((FORMAT_MESSAGE_ALLOCATE_BUFFER |
  126. FORMAT_MESSAGE_FROM_SYSTEM |
  127. FORMAT_MESSAGE_IGNORE_INSERTS |
  128. (FORMAT_MESSAGE_MAX_WIDTH_MASK & 0)),
  129. NULL,
  130. status,
  131. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  132. (LPSTR) &buffer,
  133. 1,
  134. NULL);
  135. if(length != 0) {
  136. puts(buffer);
  137. LocalFree(buffer);
  138. }
  139. }
  140. }
  141. if(!matchAll) {
  142. LPSTR header = "Option flag not understood:";
  143. while(options[0] != '\0') {
  144. if(options[0] != ' ') {
  145. printf("%s %c", header, options[0]);
  146. header = "";
  147. }
  148. options += 1;
  149. }
  150. }
  151. CloseHandle(job);
  152. return ERROR_SUCCESS;
  153. }
  154. DWORD
  155. DumpJobObjectBasicProcessIdList(
  156. HANDLE Job,
  157. JOBOBJECTINFOCLASS InfoClass
  158. )
  159. {
  160. JOBOBJECT_BASIC_PROCESS_ID_LIST buffer;
  161. PJOBOBJECT_BASIC_PROCESS_ID_LIST idList = NULL;
  162. ULONG bufferSize;
  163. BOOL result;
  164. DWORD status;
  165. DWORD i;
  166. result = QueryInformationJobObject(Job,
  167. InfoClass,
  168. &buffer,
  169. sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST),
  170. NULL);
  171. status = GetLastError();
  172. if((!result) && (status != ERROR_MORE_DATA)) {
  173. return status;
  174. }
  175. do {
  176. if(idList != NULL) {
  177. buffer.NumberOfAssignedProcesses =
  178. idList->NumberOfAssignedProcesses;
  179. LocalFree(idList);
  180. idList = NULL;
  181. }
  182. //
  183. // Calculate the actual size of the list and allocate a buffer to hold it.
  184. //
  185. bufferSize = offsetof(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList);
  186. bufferSize += sizeof(ULONG_PTR) * buffer.NumberOfAssignedProcesses;
  187. assert(idList == NULL);
  188. idList = LocalAlloc(LPTR, bufferSize);
  189. if(idList == NULL) {
  190. return GetLastError();
  191. }
  192. result = QueryInformationJobObject(Job,
  193. InfoClass,
  194. idList,
  195. bufferSize,
  196. NULL);
  197. status = GetLastError();
  198. if((!result) && (status != ERROR_MORE_DATA)) {
  199. LocalFree(idList);
  200. return status;
  201. }
  202. } while(idList->NumberOfAssignedProcesses >
  203. idList->NumberOfProcessIdsInList);
  204. assert(idList->NumberOfAssignedProcesses ==
  205. idList->NumberOfProcessIdsInList);
  206. //
  207. // Dump the information.
  208. //
  209. printf(" %d processes assigned to job:\n",
  210. idList->NumberOfAssignedProcesses);
  211. for(i = 0; i < idList->NumberOfAssignedProcesses; i++) {
  212. printf("%8d", idList->ProcessIdList[i]);
  213. PrintProcessInfo(idList->ProcessIdList[i]);
  214. puts("");
  215. }
  216. FreeProcessInfo();
  217. LocalFree(idList);
  218. return ERROR_SUCCESS;
  219. }
  220. DWORD
  221. DumpJobObjectBasicUIRestrictions(
  222. HANDLE Job,
  223. JOBOBJECTINFOCLASS InfoClass
  224. )
  225. {
  226. JOBOBJECT_BASIC_UI_RESTRICTIONS uiLimit;
  227. static FLAG_NAME jobUiLimitFlags[] = {
  228. FLAG_NAME(JOB_OBJECT_UILIMIT_HANDLES ), //0x00000001
  229. FLAG_NAME(JOB_OBJECT_UILIMIT_READCLIPBOARD ), //0x00000002
  230. FLAG_NAME(JOB_OBJECT_UILIMIT_WRITECLIPBOARD ), //0x00000004
  231. FLAG_NAME(JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS ), //0x00000008
  232. FLAG_NAME(JOB_OBJECT_UILIMIT_DISPLAYSETTINGS ), //0x00000010
  233. FLAG_NAME(JOB_OBJECT_UILIMIT_GLOBALATOMS ), //0x00000020
  234. FLAG_NAME(JOB_OBJECT_UILIMIT_DESKTOP ), //0x00000040
  235. FLAG_NAME(JOB_OBJECT_UILIMIT_EXITWINDOWS ), //0x00000080
  236. {0,0}
  237. };
  238. BOOL result;
  239. DWORD status;
  240. DWORD i;
  241. result = QueryInformationJobObject(Job,
  242. InfoClass,
  243. &uiLimit,
  244. sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS),
  245. NULL);
  246. status = GetLastError();
  247. if(!result) {
  248. return status;
  249. }
  250. if(uiLimit.UIRestrictionsClass == JOB_OBJECT_UILIMIT_NONE) {
  251. printf(" Job has no UI restrictions\n");
  252. return ERROR_SUCCESS;
  253. }
  254. DumpFlags(2,
  255. "UI Restrictions",
  256. uiLimit.UIRestrictionsClass,
  257. jobUiLimitFlags);
  258. return ERROR_SUCCESS;
  259. }
  260. DWORD
  261. DumpJobObjectBasicAndIoAccountingInformation(
  262. HANDLE Job,
  263. JOBOBJECTINFOCLASS InfoClass
  264. )
  265. {
  266. JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION info;
  267. BOOL result;
  268. DWORD status;
  269. DWORD i;
  270. result = QueryInformationJobObject(
  271. Job,
  272. InfoClass,
  273. &info,
  274. sizeof(JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION),
  275. NULL);
  276. status = GetLastError();
  277. if(!result) {
  278. return status;
  279. }
  280. xprintf(2, "Basic Info\n");
  281. xprintf(4, "TotalUserTime: %s\n", TicksToString(info.BasicInfo.TotalUserTime));
  282. xprintf(4, "TotalKernelTime: %s\n", TicksToString(info.BasicInfo.TotalKernelTime));
  283. xprintf(4, "ThisPeriodTotalUserTime: %s\n", TicksToString(info.BasicInfo.ThisPeriodTotalUserTime));
  284. xprintf(4, "ThisPeriodTotalKernelTime: %s\n", TicksToString(info.BasicInfo.ThisPeriodTotalKernelTime));
  285. xprintf(4, "TotalPageFaultCount: %d\n", info.BasicInfo.TotalPageFaultCount);
  286. xprintf(4, "TotalProcesses: %d\n", info.BasicInfo.TotalProcesses);
  287. xprintf(4, "ActiveProcesses: %d\n", info.BasicInfo.ActiveProcesses);
  288. xprintf(4, "TotalTerminatedProcesses: %d\n", info.BasicInfo.TotalTerminatedProcesses);
  289. xprintf(2, "I/O Info\n");
  290. xprintf(4, "ReadOperationCount: %I64d\n", info.IoInfo.ReadOperationCount);
  291. xprintf(4, "WriteOperationCount: %I64d\n", info.IoInfo.WriteOperationCount);
  292. xprintf(4, "OtherOperationCount: %I64d\n", info.IoInfo.OtherOperationCount);
  293. xprintf(4, "ReadTransferCount: %I64d\n", info.IoInfo.ReadTransferCount);
  294. xprintf(4, "WriteTransferCount: %I64d\n", info.IoInfo.WriteTransferCount);
  295. xprintf(4, "OtherTransferCount: %I64d\n", info.IoInfo.OtherTransferCount);
  296. return ERROR_SUCCESS;
  297. }
  298. DWORD
  299. DumpJobObjectExtendedLimitInformation(
  300. HANDLE Job,
  301. JOBOBJECTINFOCLASS InfoClass
  302. )
  303. {
  304. JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
  305. ULONG limits;
  306. static FLAG_NAME basicJobLimitFlags[] = {
  307. FLAG_NAME(JOB_OBJECT_LIMIT_WORKINGSET ), //0x00000001
  308. FLAG_NAME(JOB_OBJECT_LIMIT_PROCESS_TIME ), //0x00000002
  309. FLAG_NAME(JOB_OBJECT_LIMIT_JOB_TIME ), //0x00000004
  310. FLAG_NAME(JOB_OBJECT_LIMIT_ACTIVE_PROCESS ), //0x00000008
  311. FLAG_NAME(JOB_OBJECT_LIMIT_AFFINITY ), //0x00000010
  312. FLAG_NAME(JOB_OBJECT_LIMIT_PRIORITY_CLASS ), //0x00000020
  313. FLAG_NAME(JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME ), //0x00000040
  314. FLAG_NAME(JOB_OBJECT_LIMIT_SCHEDULING_CLASS ), //0x00000080
  315. {0,0}
  316. };
  317. //
  318. // Extended Limits
  319. //
  320. static FLAG_NAME extendedJobLimitFlags[] = {
  321. FLAG_NAME(JOB_OBJECT_LIMIT_PROCESS_MEMORY ), //0x00000100
  322. FLAG_NAME(JOB_OBJECT_LIMIT_JOB_MEMORY ), //0x00000200
  323. FLAG_NAME(JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION ), //0x00000400
  324. FLAG_NAME(JOB_OBJECT_LIMIT_BREAKAWAY_OK ), //0x00000800
  325. FLAG_NAME(JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK ), //0x00001000
  326. FLAG_NAME(JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE ), //0x00002000
  327. FLAG_NAME(JOB_OBJECT_LIMIT_RESERVED2 ), //0x00004000
  328. FLAG_NAME(JOB_OBJECT_LIMIT_RESERVED3 ), //0x00008000
  329. FLAG_NAME(JOB_OBJECT_LIMIT_RESERVED4 ), //0x00010000
  330. FLAG_NAME(JOB_OBJECT_LIMIT_RESERVED5 ), //0x00020000
  331. FLAG_NAME(JOB_OBJECT_LIMIT_RESERVED6 ), //0x00040000
  332. {0,0}
  333. };
  334. BOOL result;
  335. DWORD status;
  336. DWORD i;
  337. result = QueryInformationJobObject(
  338. Job,
  339. InfoClass,
  340. &info,
  341. sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
  342. NULL);
  343. status = GetLastError();
  344. if(!result) {
  345. return status;
  346. }
  347. limits = info.BasicLimitInformation.LimitFlags;
  348. if(TEST_FLAG(limits, JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS) == 0) {
  349. xprintf(2, "No basic limits on job\n");
  350. } else {
  351. DumpFlags(2, "Basic Limit Flags", limits & JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS, basicJobLimitFlags);
  352. if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_PROCESS_TIME)) {
  353. xprintf(4, "PerProcessUserTimeLimit: %s\n", TicksToString(info.BasicLimitInformation.PerProcessUserTimeLimit));
  354. }
  355. if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_JOB_TIME)) {
  356. xprintf(4, "PerJobUserTimeLimit: %s\n", TicksToString(info.BasicLimitInformation.PerJobUserTimeLimit));
  357. }
  358. if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_WORKINGSET)) {
  359. xprintf(4, "MinimumWorkingSetSize: %I64d\n", (ULONGLONG) info.BasicLimitInformation.MinimumWorkingSetSize);
  360. xprintf(4, "MaximumWorkingSetSize: %I64d\n", (ULONGLONG) info.BasicLimitInformation.MaximumWorkingSetSize);
  361. }
  362. if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_ACTIVE_PROCESS)) {
  363. xprintf(4, "ActiveProcessLimit: %d\n",info.BasicLimitInformation.ActiveProcessLimit);
  364. }
  365. if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_AFFINITY)) {
  366. xprintf(4, "Affinity: %#I64x\n", (ULONGLONG)info.BasicLimitInformation.Affinity);
  367. }
  368. if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_PRIORITY_CLASS)) {
  369. xprintf(4, "PriorityClass: %d\n",info.BasicLimitInformation.PriorityClass);
  370. }
  371. if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_SCHEDULING_CLASS)) {
  372. xprintf(4, "SchedulingClass: %d\n",info.BasicLimitInformation.SchedulingClass);
  373. }
  374. }
  375. if(TEST_FLAG(limits, JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS) == 0) {
  376. xprintf(2, "No extended limits on job\n");
  377. } else {
  378. DumpFlags(2, "Extended Limit Flags", limits & JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS & ~JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS, extendedJobLimitFlags);
  379. if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_PROCESS_MEMORY)) {
  380. xprintf(4, "ProcessMemoryLimit: %I64d\n", (ULONGLONG) info.ProcessMemoryLimit);
  381. }
  382. if(TEST_FLAG(limits, JOB_OBJECT_LIMIT_PROCESS_MEMORY)) {
  383. xprintf(4, "JobMemoryLimit: %I64d\n", (ULONGLONG) info.JobMemoryLimit);
  384. }
  385. }
  386. xprintf(2, "PeakProcessMemoryUsed: %I64d\n", (ULONGLONG) info.PeakProcessMemoryUsed);
  387. xprintf(2, "PeakJobMemoryUsed: %I64d\n", (ULONGLONG) info.PeakJobMemoryUsed);
  388. return ERROR_SUCCESS;
  389. }
  390. DWORD
  391. DumpJobObjectSecurityLimitInformation(
  392. HANDLE Job,
  393. JOBOBJECTINFOCLASS InfoClass
  394. )
  395. {
  396. JOBOBJECT_SECURITY_LIMIT_INFORMATION buffer;
  397. PJOBOBJECT_SECURITY_LIMIT_INFORMATION info = NULL;
  398. static FLAG_NAME jobSecurityLimitFlags[] = {
  399. FLAG_NAME(JOB_OBJECT_SECURITY_NO_ADMIN ), //00000001
  400. FLAG_NAME(JOB_OBJECT_SECURITY_RESTRICTED_TOKEN ), //00000002
  401. FLAG_NAME(JOB_OBJECT_SECURITY_ONLY_TOKEN ), //00000004
  402. FLAG_NAME(JOB_OBJECT_SECURITY_FILTER_TOKENS ), //00000008
  403. {0, 0}
  404. };
  405. ULONG bufferSize;
  406. BOOL result;
  407. DWORD status;
  408. DWORD i;
  409. result = QueryInformationJobObject(
  410. Job,
  411. InfoClass,
  412. &buffer,
  413. sizeof(JOBOBJECT_SECURITY_LIMIT_INFORMATION),
  414. &bufferSize);
  415. status = GetLastError();
  416. if((!result) && (status != ERROR_MORE_DATA)) {
  417. return status;
  418. }
  419. info = LocalAlloc(LPTR, bufferSize);
  420. if(info == NULL) {
  421. return GetLastError();
  422. }
  423. result = QueryInformationJobObject(Job, InfoClass, info, bufferSize, NULL);
  424. if(!result) {
  425. status = GetLastError();
  426. LocalFree(info);
  427. return status;
  428. }
  429. if(info->SecurityLimitFlags == 0) {
  430. xprintf(2, "No security limitations on job\n");
  431. } else {
  432. DumpFlags(2, "SecurityLimitFlags", info->SecurityLimitFlags, jobSecurityLimitFlags);
  433. }
  434. LocalFree(info);
  435. return ERROR_SUCCESS;
  436. }