auxMessage
[reactos.git] / rosapps / sysutils / tlist / tlist.c
1 /*
2 * ReactOS Project
3 * TList
4 *
5 * Copyright (c) 2000,2001 Emanuele Aliberti
6 */
7 #include <reactos/buildno.h>
8 #include <windows.h>
9 #define NTOS_MODE_USER
10 #include <ndk/ntndk.h>
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16
17 #include <epsapi/epsapi.h>
18 #include <getopt.h>
19
20 #ifndef PAGE_SIZE
21 #define PAGE_SIZE 4096
22 #endif
23
24 #define ALREADY_PROCESSED ((DWORD)-1)
25
26 LPWSTR ThreadStateName [] =
27 {
28 L"Initialized",
29 L"Ready",
30 L"Running",
31 L"Standby",
32 L"Terminated",
33 L"Wait",
34 L"Transition",
35 L"Unknown",
36 NULL
37 };
38
39 void *PsaiMalloc(SIZE_T size)
40 {
41 void * pBuf = NULL;
42 NTSTATUS nErrCode;
43
44 nErrCode = NtAllocateVirtualMemory
45 (
46 NtCurrentProcess(),
47 &pBuf,
48 0,
49 (PULONG)&size,
50 MEM_COMMIT,
51 PAGE_READWRITE
52 );
53
54 if(NT_SUCCESS(nErrCode)) return pBuf;
55 else return NULL;
56 }
57
58 void PsaiFree(void *ptr)
59 {
60 ULONG nSize = 0;
61
62 NtFreeVirtualMemory(NtCurrentProcess(), &ptr, &nSize, MEM_RELEASE);
63 }
64
65 int STDCALL PrintBanner (VOID)
66 {
67 printf ("ReactOS "KERNEL_RELEASE_STR" T(ask)List\n");
68 printf ("Copyright (c) 2000,2001 Emanuele Aliberti\n\n");
69 return EXIT_SUCCESS;
70 }
71
72 int STDCALL PrintSynopsys (int nRetVal)
73 {
74 PrintBanner ();
75 printf ("Usage: tlist [-t | PID | -l]\n\n"
76 " -t print the task list tree\n"
77 " PID print module information for this ID\n"
78 " -l print license information\n");
79 return nRetVal;
80 }
81
82 int STDCALL PrintLicense (VOID)
83 {
84 PrintBanner ();
85 printf (
86 "This program is free software; you can redistribute it and/or modify\n"
87 "it under the terms of the GNU General Public License as published by\n"
88 "the Free Software Foundation; either version 2 of the License, or\n"
89 "(at your option) any later version.\n\n");
90 printf (
91 "This program is distributed in the hope that it will be useful,\n"
92 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
93 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
94 "GNU General Public License for more details.\n\n");
95 printf (
96 "You should have received a copy of the GNU General Public License\n"
97 "along with this program; if not, write to the Free Software\n"
98 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
99 return EXIT_SUCCESS;
100 }
101
102 BOOL STDCALL AcquirePrivileges (VOID)
103 {
104 /* TODO: implement it */
105 return TRUE;
106 }
107
108 int STDCALL
109 ProcessHasDescendants (
110 HANDLE Pid,
111 PSYSTEM_PROCESS_INFORMATION pInfo
112 )
113 {
114 LONG Count = 0;
115
116 if (NULL == pInfo) return 0;
117 do {
118
119 if (ALREADY_PROCESSED != (DWORD)pInfo->InheritedFromUniqueProcessId)
120 {
121 if ((Pid != (HANDLE)pInfo->UniqueProcessId) && (Pid == (HANDLE)pInfo->InheritedFromUniqueProcessId))
122 {
123 ++ Count;
124 }
125 }
126 pInfo = (PSYSTEM_PROCESS_INFORMATION)((PBYTE)pInfo + pInfo->NextEntryOffset);
127
128 } while (0 != pInfo->NextEntryOffset);
129
130 return Count;
131 }
132
133
134 BOOL STDCALL
135 GetProcessInfo (
136 PSYSTEM_PROCESS_INFORMATION pInfo,
137 LPWSTR * Module,
138 LPWSTR * Title
139 )
140 {
141 *Module = (pInfo->ImageName.Length ? pInfo->ImageName.Buffer : L"System process");
142 *Title = L""; /* TODO: check if the process has any window */
143 return TRUE;
144 }
145
146 int STDCALL PrintProcessInfoDepth (
147 PSYSTEM_PROCESS_INFORMATION pInfo,
148 LONG Depth
149 )
150 {
151 INT d = 0;
152 LPWSTR Module = L"";
153 LPWSTR Title = L"";
154
155 for (d = 0; d < Depth; d ++) printf (" ");
156 GetProcessInfo (pInfo, & Module, & Title);
157 wprintf (
158 L"%s (%d, %d) %s\n",
159 Module,
160 pInfo->UniqueProcessId,
161 pInfo->InheritedFromUniqueProcessId,
162 Title
163 );
164 return EXIT_SUCCESS;
165 }
166
167 int STDCALL
168 PrintProcessAndDescendants (
169 PSYSTEM_PROCESS_INFORMATION pInfo,
170 PSYSTEM_PROCESS_INFORMATION pInfoBase,
171 LONG Depth
172 )
173 {
174 HANDLE Pid = 0;
175
176 if (NULL == pInfo) return EXIT_FAILURE;
177 /* Print current pInfo process */
178 PrintProcessInfoDepth (pInfo, Depth ++);
179 pInfo->InheritedFromUniqueProcessId = (HANDLE)ALREADY_PROCESSED;
180 /* Save current process' PID */
181 Pid = pInfo->UniqueProcessId;
182 /* Scan and print possible children */
183 do {
184
185 if (ALREADY_PROCESSED != (DWORD)pInfo->InheritedFromUniqueProcessId)
186 {
187 if (Pid == pInfo->InheritedFromUniqueProcessId)
188 {
189 if (ProcessHasDescendants (Pid, pInfoBase))
190 {
191 PrintProcessAndDescendants (
192 pInfo,
193 pInfoBase,
194 Depth
195 );
196 }
197 else
198 {
199 PrintProcessInfoDepth (pInfo, Depth);
200 pInfo->InheritedFromUniqueProcessId = (HANDLE)ALREADY_PROCESSED;
201 }
202 }
203 }
204 pInfo = (PSYSTEM_PROCESS_INFORMATION)((PBYTE)pInfo + pInfo->NextEntryOffset);
205
206 } while (0 != pInfo->NextEntryOffset);
207
208 return EXIT_SUCCESS;
209 }
210
211 int STDCALL PrintProcessList (BOOL DisplayTree)
212 {
213 PSYSTEM_PROCESS_INFORMATION pInfo = NULL;
214 PSYSTEM_PROCESS_INFORMATION pInfoBase = NULL;
215 LPWSTR Module = L"";
216 LPWSTR Title = L"";
217
218 if (!NT_SUCCESS(PsaCaptureProcessesAndThreads(&pInfoBase)))
219 return EXIT_FAILURE;
220
221 pInfo = PsaWalkFirstProcess(pInfoBase);
222
223 while (pInfo)
224 {
225 if (FALSE == DisplayTree)
226 {
227 GetProcessInfo (pInfo, & Module, & Title);
228 wprintf (
229 L"%4d %-16s %s\n",
230 pInfo->UniqueProcessId,
231 Module,
232 Title,
233 pInfo->InheritedFromUniqueProcessId
234 );
235 }
236 else
237 {
238 if (ALREADY_PROCESSED != (DWORD)pInfo->InheritedFromUniqueProcessId)
239 {
240 PrintProcessAndDescendants (pInfo, pInfoBase, 0);
241 }
242 }
243
244 pInfo = PsaWalkNextProcess(pInfo);
245 }
246
247 PsaFreeCapture(pInfoBase);
248
249 return EXIT_SUCCESS;
250 }
251
252
253 int STDCALL PrintThreads (PSYSTEM_PROCESS_INFORMATION pInfo)
254 {
255 ULONG i = 0;
256 NTSTATUS Status = STATUS_SUCCESS;
257 HANDLE hThread = INVALID_HANDLE_VALUE;
258 OBJECT_ATTRIBUTES Oa = {0};
259 PVOID Win32StartAddress = NULL;
260 THREAD_BASIC_INFORMATION tInfo = {0};
261 ULONG ReturnLength = 0;
262 PSYSTEM_THREAD_INFORMATION CurThread;
263
264 if (NULL == pInfo) return EXIT_FAILURE;
265
266 CurThread = PsaWalkFirstThread(pInfo);
267
268 wprintf (L" NumberOfThreads: %d\n", pInfo->NumberOfThreads);
269
270 for (i = 0; i < pInfo->NumberOfThreads; i ++, CurThread = PsaWalkNextThread(CurThread))
271 {
272 Status = NtOpenThread (
273 & hThread,
274 THREAD_QUERY_INFORMATION,
275 & Oa,
276 & CurThread->ClientId
277 );
278 if (!NT_SUCCESS(Status))
279 {
280 continue;
281 }
282
283 Status = NtQueryInformationThread (
284 hThread,
285 ThreadBasicInformation,
286 (PVOID) & tInfo,
287 sizeof tInfo,
288 & ReturnLength
289 );
290 if (!NT_SUCCESS(Status))
291 {
292 NtClose (hThread);
293 continue;
294 }
295
296 Status = NtQueryInformationThread (
297 hThread,
298 ThreadQuerySetWin32StartAddress,
299 (PVOID) & Win32StartAddress,
300 sizeof Win32StartAddress,
301 & ReturnLength
302 );
303 if (!NT_SUCCESS(Status))
304 {
305 NtClose (hThread);
306 continue;
307 }
308
309 NtClose (hThread);
310
311 /* Now print the collected information */
312 wprintf (L" %4d Win32StartAddr:0x%08x LastErr:0x%08x State:%s\n",
313 CurThread->ClientId.UniqueThread,
314 Win32StartAddress,
315 0 /* FIXME: ((PTEB) tInfo.TebBaseAddress)->LastErrorValue */,
316 ThreadStateName[CurThread->ThreadState]
317 );
318 }
319 return EXIT_SUCCESS;
320 }
321
322 int STDCALL PrintModules (VOID)
323 {
324 /* TODO */
325 return EXIT_SUCCESS;
326 }
327
328 PSYSTEM_PROCESS_INFORMATION STDCALL
329 GetProcessInfoPid (
330 PSYSTEM_PROCESS_INFORMATION pInfoBase,
331 HANDLE Pid
332 )
333 {
334 if (NULL == pInfoBase) return NULL;
335
336 pInfoBase = PsaWalkFirstProcess(pInfoBase);
337
338 while(pInfoBase)
339 {
340 if (Pid == pInfoBase->UniqueProcessId)
341 {
342 return pInfoBase;
343 }
344
345 pInfoBase = PsaWalkNextProcess(pInfoBase);
346 }
347
348 return NULL;
349 }
350
351 int STDCALL PrintProcess (char * PidStr)
352 {
353 NTSTATUS Status = 0;
354 HANDLE hProcess = 0;
355 OBJECT_ATTRIBUTES Oa = {0};
356 CLIENT_ID ClientId = {0, 0};
357
358
359 ClientId.UniqueProcess = (PVOID) atol (PidStr);
360
361 if (FALSE == AcquirePrivileges ())
362 {
363 return EXIT_FAILURE;
364 }
365
366 Status = NtOpenProcess (
367 & hProcess,
368 PROCESS_QUERY_INFORMATION,
369 & Oa,
370 & ClientId
371 );
372 if (NT_SUCCESS(Status))
373 {
374 ULONG ReturnLength = 0;
375 PROCESS_BASIC_INFORMATION PsBasic;
376 VM_COUNTERS PsVm;
377 PSYSTEM_PROCESS_INFORMATION pInfo = NULL;
378 PSYSTEM_PROCESS_INFORMATION pInfoBase = NULL;
379 LPWSTR Module = L"";
380 LPWSTR Title = L"";
381
382 Status = NtQueryInformationProcess (
383 hProcess,
384 ProcessBasicInformation,
385 & PsBasic,
386 sizeof (PsBasic),
387 & ReturnLength
388 );
389 if (!NT_SUCCESS(Status))
390 {
391 return EXIT_FAILURE;
392 }
393 Status = NtQueryInformationProcess (
394 hProcess,
395 ProcessVmCounters,
396 & PsVm,
397 sizeof (PsVm),
398 & ReturnLength
399 );
400 if (!NT_SUCCESS(Status))
401 {
402 return EXIT_FAILURE;
403 }
404
405 if (!NT_SUCCESS(PsaCaptureProcessesAndThreads (&pInfoBase)))
406 return EXIT_FAILURE;
407
408 pInfo = GetProcessInfoPid (pInfoBase, ClientId.UniqueProcess);
409 if (NULL == pInfo) return EXIT_FAILURE;
410
411 GetProcessInfo (pInfo, & Module, & Title);
412
413 wprintf (L"%4d %s\n", ClientId.UniqueProcess, Module);
414 #if 0
415 printf (" CWD: %s\n", ""); /* it won't appear if empty */
416 printf (" CmdLine: %s\n", ""); /* it won't appear if empty */
417 #endif
418 printf (" VirtualSize: %5ld kb PeakVirtualSize: %5ld kb\n",
419 ((LONG) PsVm.VirtualSize / 1024),
420 ((LONG) PsVm.PeakVirtualSize / 1024)
421 );
422 printf (" WorkingSetSize: %5ld kb PeakWorkingSetSize: %5ld kb\n",
423 ((LONG) PsVm.WorkingSetSize / 1024),
424 ((LONG) PsVm.PeakWorkingSetSize / 1024)
425 );
426
427 PrintThreads (pInfo);
428
429 PrintModules ();
430
431 PsaFreeCapture(pInfoBase);
432
433 NtClose (hProcess);
434
435 return EXIT_SUCCESS;
436 }
437 return EXIT_FAILURE;
438 }
439
440
441 int main (int argc, char * argv [])
442 {
443 int c;
444
445 if(1 == argc) return PrintProcessList(FALSE);
446
447 while((c = getopt(argc, argv, "tl")) != -1)
448 {
449 switch(c)
450 {
451 case 't': return PrintProcessList(TRUE);
452 case 'l': return PrintLicense();
453 default: return PrintSynopsys(EXIT_FAILURE);
454 }
455 }
456
457 if(isdigit(argv[optind][0]))
458 return PrintProcess (argv[1]);
459
460 return PrintSynopsys(EXIT_SUCCESS);
461 }
462
463 /* EOF */