3a95d7dc0dfc13835cf5df485cd3f986a99d7e9a
[reactos.git] / rosapps / sysutils / tlist / tlist.c
1 /* $Id: tlist.c,v 1.6 2003/08/03 18:06:02 ea Exp $
2 *
3 * ReactOS Project
4 * TList
5 *
6 * Copyright (c) 2000,2001 Emanuele Aliberti
7 */
8 #include <reactos/buildno.h>
9 #define NTOS_MODE_USER
10 #include <ntos.h>
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16
17 #include <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 ULONG Pid,
111 PSYSTEM_PROCESSES pInfo
112 )
113 {
114 LONG Count = 0;
115
116 if (NULL == pInfo) return 0;
117 do {
118
119 if (ALREADY_PROCESSED != pInfo->InheritedFromProcessId)
120 {
121 if ((Pid != pInfo->ProcessId) && (Pid == pInfo->InheritedFromProcessId))
122 {
123 ++ Count;
124 }
125 }
126 (PBYTE) pInfo += pInfo->NextEntryDelta;
127
128 } while (0 != pInfo->NextEntryDelta);
129
130 return Count;
131 }
132
133
134 BOOL STDCALL
135 GetProcessInfo (
136 PSYSTEM_PROCESSES pInfo,
137 LPWSTR * Module,
138 LPWSTR * Title
139 )
140 {
141 *Module = (pInfo->ProcessName.Length ? pInfo->ProcessName.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_PROCESSES 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->ProcessId,
161 pInfo->InheritedFromProcessId,
162 Title
163 );
164 return EXIT_SUCCESS;
165 }
166
167 int STDCALL
168 PrintProcessAndDescendants (
169 PSYSTEM_PROCESSES pInfo,
170 PSYSTEM_PROCESSES pInfoBase,
171 LONG Depth
172 )
173 {
174 DWORD Pid = 0;
175
176 if (NULL == pInfo) return EXIT_FAILURE;
177 /* Print current pInfo process */
178 PrintProcessInfoDepth (pInfo, Depth ++);
179 pInfo->InheritedFromProcessId = ALREADY_PROCESSED;
180 /* Save current process' PID */
181 Pid = pInfo->ProcessId;
182 /* Scan and print possible children */
183 do {
184
185 if (ALREADY_PROCESSED != pInfo->InheritedFromProcessId)
186 {
187 if (Pid == pInfo->InheritedFromProcessId)
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->InheritedFromProcessId = ALREADY_PROCESSED;
201 }
202 }
203 }
204 (PBYTE) pInfo += pInfo->NextEntryDelta;
205
206 } while (0 != pInfo->NextEntryDelta);
207
208 return EXIT_SUCCESS;
209 }
210
211 int STDCALL PrintProcessList (BOOL DisplayTree)
212 {
213 PSYSTEM_PROCESSES pInfo = NULL;
214 PSYSTEM_PROCESSES pInfoBase = NULL;
215 LONG Length = 0;
216 LPWSTR Module = L"";
217 LPWSTR Title = L"";
218
219 if (!NT_SUCCESS(PsaCaptureProcessesAndThreads(&pInfoBase)))
220 return EXIT_FAILURE;
221
222 pInfo = PsaWalkFirstProcess(pInfoBase);
223
224 while (pInfo)
225 {
226 if (FALSE == DisplayTree)
227 {
228 GetProcessInfo (pInfo, & Module, & Title);
229 wprintf (
230 L"%4d %-16s %s\n",
231 pInfo->ProcessId,
232 Module,
233 Title,
234 pInfo->InheritedFromProcessId
235 );
236 }
237 else
238 {
239 if (ALREADY_PROCESSED != pInfo->InheritedFromProcessId)
240 {
241 PrintProcessAndDescendants (pInfo, pInfoBase, 0);
242 }
243 }
244
245 pInfo = PsaWalkNextProcess(pInfo);
246 }
247
248 PsaFreeCapture(pInfoBase);
249
250 return EXIT_SUCCESS;
251 }
252
253
254 int STDCALL PrintThreads (PSYSTEM_PROCESSES pInfo)
255 {
256 ULONG i = 0;
257 NTSTATUS Status = STATUS_SUCCESS;
258 HANDLE hThread = INVALID_HANDLE_VALUE;
259 OBJECT_ATTRIBUTES Oa = {0};
260 PVOID Win32StartAddress = NULL;
261 THREAD_BASIC_INFORMATION tInfo = {0};
262 ULONG ReturnLength = 0;
263 PSYSTEM_THREADS CurThread;
264
265 if (NULL == pInfo) return EXIT_FAILURE;
266
267 CurThread = PsaWalkFirstThread(pInfo);
268
269 wprintf (L" NumberOfThreads: %d\n", pInfo->ThreadCount);
270
271 for (i = 0; i < pInfo->ThreadCount; i ++, CurThread = PsaWalkNextThread(CurThread))
272 {
273 Status = NtOpenThread (
274 & hThread,
275 THREAD_QUERY_INFORMATION,
276 & Oa,
277 & CurThread->ClientId
278 );
279 if (!NT_SUCCESS(Status))
280 {
281 continue;
282 }
283
284 Status = NtQueryInformationThread (
285 hThread,
286 ThreadBasicInformation,
287 (PVOID) & tInfo,
288 sizeof tInfo,
289 & ReturnLength
290 );
291 if (!NT_SUCCESS(Status))
292 {
293 NtClose (hThread);
294 continue;
295 }
296
297 Status = NtQueryInformationThread (
298 hThread,
299 ThreadQuerySetWin32StartAddress,
300 (PVOID) & Win32StartAddress,
301 sizeof Win32StartAddress,
302 & ReturnLength
303 );
304 if (!NT_SUCCESS(Status))
305 {
306 NtClose (hThread);
307 continue;
308 }
309
310 NtClose (hThread);
311
312 /* Now print the collected information */
313 wprintf (L" %4d Win32StartAddr:0x%08x LastErr:0x%08x State:%s\n",
314 CurThread->ClientId.UniqueThread,
315 Win32StartAddress,
316 0 /* FIXME: ((PTEB) tInfo.TebBaseAddress)->LastErrorValue */,
317 ThreadStateName[CurThread->State]
318 );
319 }
320 return EXIT_SUCCESS;
321 }
322
323 int STDCALL PrintModules (VOID)
324 {
325 /* TODO */
326 return EXIT_SUCCESS;
327 }
328
329 PSYSTEM_PROCESSES STDCALL
330 GetProcessInfoPid (
331 PSYSTEM_PROCESSES pInfoBase,
332 DWORD Pid
333 )
334 {
335 if (NULL == pInfoBase) return NULL;
336
337 pInfoBase = PsaWalkFirstProcess(pInfoBase);
338
339 while(pInfoBase)
340 {
341 if (Pid == pInfoBase->ProcessId)
342 {
343 return pInfoBase;
344 }
345
346 pInfoBase = PsaWalkNextProcess(pInfoBase);
347 }
348
349 return NULL;
350 }
351
352 int STDCALL PrintProcess (char * PidStr)
353 {
354 NTSTATUS Status = 0;
355 HANDLE hProcess = 0;
356 OBJECT_ATTRIBUTES Oa = {0};
357 CLIENT_ID ClientId = {0, 0};
358
359
360 ClientId.UniqueProcess = (PVOID) atol (PidStr);
361
362 if (FALSE == AcquirePrivileges ())
363 {
364 return EXIT_FAILURE;
365 }
366
367 Status = NtOpenProcess (
368 & hProcess,
369 PROCESS_QUERY_INFORMATION,
370 & Oa,
371 & ClientId
372 );
373 if (NT_SUCCESS(Status))
374 {
375 ULONG ReturnLength = 0;
376 PROCESS_BASIC_INFORMATION PsBasic;
377 VM_COUNTERS PsVm;
378 PSYSTEM_PROCESSES pInfo = NULL;
379 PSYSTEM_PROCESSES pInfoBase = NULL;
380 LONG pInfoBaseLength = 0;
381 LPWSTR Module = L"";
382 LPWSTR Title = L"";
383
384 Status = NtQueryInformationProcess (
385 hProcess,
386 ProcessBasicInformation,
387 & PsBasic,
388 sizeof (PsBasic),
389 & ReturnLength
390 );
391 if (!NT_SUCCESS(Status))
392 {
393 return EXIT_FAILURE;
394 }
395 Status = NtQueryInformationProcess (
396 hProcess,
397 ProcessVmCounters,
398 & PsVm,
399 sizeof (PsVm),
400 & ReturnLength
401 );
402 if (!NT_SUCCESS(Status))
403 {
404 return EXIT_FAILURE;
405 }
406
407 if (!NT_SUCCESS(PsaCaptureProcessesAndThreads (&pInfoBase)))
408 return EXIT_FAILURE;
409
410 pInfo = GetProcessInfoPid (pInfoBase, (DWORD) ClientId.UniqueProcess);
411 if (NULL == pInfo) return EXIT_FAILURE;
412
413 GetProcessInfo (pInfo, & Module, & Title);
414
415 wprintf (L"%4d %s\n", ClientId.UniqueProcess, Module);
416 #if 0
417 printf (" CWD: %s\n", ""); /* it won't appear if empty */
418 printf (" CmdLine: %s\n", ""); /* it won't appear if empty */
419 #endif
420 printf (" VirtualSize: %5ld kb PeakVirtualSize: %5ld kb\n",
421 ((LONG) PsVm.VirtualSize / 1024),
422 ((LONG) PsVm.PeakVirtualSize / 1024)
423 );
424 printf (" WorkingSetSize: %5ld kb PeakWorkingSetSize: %5ld kb\n",
425 ((LONG) PsVm.WorkingSetSize / 1024),
426 ((LONG) PsVm.PeakWorkingSetSize / 1024)
427 );
428
429 PrintThreads (pInfo);
430
431 PrintModules ();
432
433 PsaFreeCapture(pInfoBase);
434
435 NtClose (hProcess);
436
437 return EXIT_SUCCESS;
438 }
439 return EXIT_FAILURE;
440 }
441
442
443 int main (int argc, char * argv [])
444 {
445 int c;
446
447 if(1 == argc) return PrintProcessList(FALSE);
448
449 while((c = getopt(argc, argv, "tl")) != -1)
450 {
451 switch(c)
452 {
453 case 't': return PrintProcessList(TRUE);
454 case 'l': return PrintLicense();
455 default: return PrintSynopsys(EXIT_FAILURE);
456 }
457 }
458
459 if(isdigit(argv[optind][0]))
460 return PrintProcess (argv[1]);
461
462 return PrintSynopsys(EXIT_SUCCESS);
463 }
464
465 /* EOF */