Merge from amd64 branch:
[reactos.git] / rosapps / applications / 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 #define WIN32_NO_STATUS
9 #include <windows.h>
10 #define NTOS_MODE_USER
11 #include <ndk/ntndk.h>
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <ctype.h>
17
18 #include <epsapi/epsapi.h>
19 #include <getopt.h>
20
21 #ifndef PAGE_SIZE
22 #define PAGE_SIZE 4096
23 #endif
24
25 #define ALREADY_PROCESSED ((DWORD)-1)
26
27 LPWSTR ThreadStateName [] =
28 {
29 L"Initialized",
30 L"Ready",
31 L"Running",
32 L"Standby",
33 L"Terminated",
34 L"Wait",
35 L"Transition",
36 L"Unknown",
37 NULL
38 };
39
40 void *PsaiMalloc(SIZE_T size)
41 {
42 void * pBuf = NULL;
43 NTSTATUS nErrCode;
44
45 nErrCode = NtAllocateVirtualMemory
46 (
47 NtCurrentProcess(),
48 &pBuf,
49 0,
50 (PULONG)&size,
51 MEM_COMMIT,
52 PAGE_READWRITE
53 );
54
55 if(NT_SUCCESS(nErrCode)) return pBuf;
56 else return NULL;
57 }
58
59 void PsaiFree(void *ptr)
60 {
61 ULONG nSize = 0;
62
63 NtFreeVirtualMemory(NtCurrentProcess(), &ptr, &nSize, MEM_RELEASE);
64 }
65
66 int WINAPI PrintBanner (VOID)
67 {
68 printf ("ReactOS "KERNEL_RELEASE_STR" T(ask)List\n");
69 printf ("Copyright (c) 2000,2001 Emanuele Aliberti\n\n");
70 return EXIT_SUCCESS;
71 }
72
73 int WINAPI PrintSynopsys (int nRetVal)
74 {
75 PrintBanner ();
76 printf ("Usage: tlist [-t | PID | -l]\n\n"
77 " -t print the task list tree\n"
78 " PID print module information for this ID\n"
79 " -l print license information\n");
80 return nRetVal;
81 }
82
83 int WINAPI PrintLicense (VOID)
84 {
85 PrintBanner ();
86 printf (
87 "This program is free software; you can redistribute it and/or modify\n"
88 "it under the terms of the GNU General Public License as published by\n"
89 "the Free Software Foundation; either version 2 of the License, or\n"
90 "(at your option) any later version.\n\n");
91 printf (
92 "This program is distributed in the hope that it will be useful,\n"
93 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
94 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
95 "GNU General Public License for more details.\n\n");
96 printf (
97 "You should have received a copy of the GNU General Public License\n"
98 "along with this program; if not, write to the Free Software\n"
99 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
100 return EXIT_SUCCESS;
101 }
102
103 BOOL WINAPI AcquirePrivileges (VOID)
104 {
105 /* TODO: implement it */
106 return TRUE;
107 }
108
109 int WINAPI
110 ProcessHasDescendants (
111 HANDLE Pid,
112 PSYSTEM_PROCESS_INFORMATION pInfo
113 )
114 {
115 LONG Count = 0;
116
117 if (NULL == pInfo) return 0;
118 do {
119
120 if (ALREADY_PROCESSED != (DWORD)pInfo->InheritedFromUniqueProcessId)
121 {
122 if ((Pid != (HANDLE)pInfo->UniqueProcessId) && (Pid == (HANDLE)pInfo->InheritedFromUniqueProcessId))
123 {
124 ++ Count;
125 }
126 }
127 pInfo = (PSYSTEM_PROCESS_INFORMATION)((PBYTE)pInfo + pInfo->NextEntryOffset);
128
129 } while (0 != pInfo->NextEntryOffset);
130
131 return Count;
132 }
133
134
135 BOOL WINAPI
136 GetProcessInfo (
137 PSYSTEM_PROCESS_INFORMATION pInfo,
138 LPWSTR * Module,
139 LPWSTR * Title
140 )
141 {
142 *Module = (pInfo->ImageName.Length ? pInfo->ImageName.Buffer : L"System process");
143 *Title = L""; /* TODO: check if the process has any window */
144 return TRUE;
145 }
146
147 int WINAPI PrintProcessInfoDepth (
148 PSYSTEM_PROCESS_INFORMATION pInfo,
149 LONG Depth
150 )
151 {
152 INT d = 0;
153 LPWSTR Module = L"";
154 LPWSTR Title = L"";
155
156 for (d = 0; d < Depth; d ++) printf (" ");
157 GetProcessInfo (pInfo, & Module, & Title);
158 wprintf (
159 L"%s (%d, %d) %s\n",
160 Module,
161 pInfo->UniqueProcessId,
162 pInfo->InheritedFromUniqueProcessId,
163 Title
164 );
165 return EXIT_SUCCESS;
166 }
167
168 int WINAPI
169 PrintProcessAndDescendants (
170 PSYSTEM_PROCESS_INFORMATION pInfo,
171 PSYSTEM_PROCESS_INFORMATION pInfoBase,
172 LONG Depth
173 )
174 {
175 HANDLE Pid = 0;
176
177 if (NULL == pInfo) return EXIT_FAILURE;
178 /* Print current pInfo process */
179 PrintProcessInfoDepth (pInfo, Depth ++);
180 pInfo->InheritedFromUniqueProcessId = (HANDLE)ALREADY_PROCESSED;
181 /* Save current process' PID */
182 Pid = pInfo->UniqueProcessId;
183 /* Scan and print possible children */
184 do {
185
186 if (ALREADY_PROCESSED != (DWORD)pInfo->InheritedFromUniqueProcessId)
187 {
188 if (Pid == pInfo->InheritedFromUniqueProcessId)
189 {
190 if (ProcessHasDescendants (Pid, pInfoBase))
191 {
192 PrintProcessAndDescendants (
193 pInfo,
194 pInfoBase,
195 Depth
196 );
197 }
198 else
199 {
200 PrintProcessInfoDepth (pInfo, Depth);
201 pInfo->InheritedFromUniqueProcessId = (HANDLE)ALREADY_PROCESSED;
202 }
203 }
204 }
205 pInfo = (PSYSTEM_PROCESS_INFORMATION)((PBYTE)pInfo + pInfo->NextEntryOffset);
206
207 } while (0 != pInfo->NextEntryOffset);
208
209 return EXIT_SUCCESS;
210 }
211
212 int WINAPI PrintProcessList (BOOL DisplayTree)
213 {
214 PSYSTEM_PROCESS_INFORMATION pInfo = NULL;
215 PSYSTEM_PROCESS_INFORMATION pInfoBase = NULL;
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->UniqueProcessId,
232 Module,
233 Title,
234 pInfo->InheritedFromUniqueProcessId
235 );
236 }
237 else
238 {
239 if (ALREADY_PROCESSED != (DWORD)pInfo->InheritedFromUniqueProcessId)
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 WINAPI PrintThreads (PSYSTEM_PROCESS_INFORMATION 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_THREAD_INFORMATION CurThread;
264
265 if (NULL == pInfo) return EXIT_FAILURE;
266
267 CurThread = PsaWalkFirstThread(pInfo);
268
269 wprintf (L" NumberOfThreads: %d\n", pInfo->NumberOfThreads);
270
271 for (i = 0; i < pInfo->NumberOfThreads; 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->ThreadState]
318 );
319 }
320 return EXIT_SUCCESS;
321 }
322
323 int WINAPI PrintModules (VOID)
324 {
325 /* TODO */
326 return EXIT_SUCCESS;
327 }
328
329 PSYSTEM_PROCESS_INFORMATION WINAPI
330 GetProcessInfoPid (
331 PSYSTEM_PROCESS_INFORMATION pInfoBase,
332 HANDLE Pid
333 )
334 {
335 if (NULL == pInfoBase) return NULL;
336
337 pInfoBase = PsaWalkFirstProcess(pInfoBase);
338
339 while(pInfoBase)
340 {
341 if (Pid == pInfoBase->UniqueProcessId)
342 {
343 return pInfoBase;
344 }
345
346 pInfoBase = PsaWalkNextProcess(pInfoBase);
347 }
348
349 return NULL;
350 }
351
352 int WINAPI 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_PROCESS_INFORMATION pInfo = NULL;
379 PSYSTEM_PROCESS_INFORMATION pInfoBase = NULL;
380 LPWSTR Module = L"";
381 LPWSTR Title = L"";
382
383 Status = NtQueryInformationProcess (
384 hProcess,
385 ProcessBasicInformation,
386 & PsBasic,
387 sizeof (PsBasic),
388 & ReturnLength
389 );
390 if (!NT_SUCCESS(Status))
391 {
392 return EXIT_FAILURE;
393 }
394 Status = NtQueryInformationProcess (
395 hProcess,
396 ProcessVmCounters,
397 & PsVm,
398 sizeof (PsVm),
399 & ReturnLength
400 );
401 if (!NT_SUCCESS(Status))
402 {
403 return EXIT_FAILURE;
404 }
405
406 if (!NT_SUCCESS(PsaCaptureProcessesAndThreads (&pInfoBase)))
407 return EXIT_FAILURE;
408
409 pInfo = GetProcessInfoPid (pInfoBase, ClientId.UniqueProcess);
410 if (NULL == pInfo) return EXIT_FAILURE;
411
412 GetProcessInfo (pInfo, & Module, & Title);
413
414 wprintf (L"%4d %s\n", ClientId.UniqueProcess, Module);
415 #if 0
416 printf (" CWD: %s\n", ""); /* it won't appear if empty */
417 printf (" CmdLine: %s\n", ""); /* it won't appear if empty */
418 #endif
419 printf (" VirtualSize: %5ld kb PeakVirtualSize: %5ld kb\n",
420 ((LONG) PsVm.VirtualSize / 1024),
421 ((LONG) PsVm.PeakVirtualSize / 1024)
422 );
423 printf (" WorkingSetSize: %5ld kb PeakWorkingSetSize: %5ld kb\n",
424 ((LONG) PsVm.WorkingSetSize / 1024),
425 ((LONG) PsVm.PeakWorkingSetSize / 1024)
426 );
427
428 PrintThreads (pInfo);
429
430 PrintModules ();
431
432 PsaFreeCapture(pInfoBase);
433
434 NtClose (hProcess);
435
436 return EXIT_SUCCESS;
437 }
438 return EXIT_FAILURE;
439 }
440
441
442 int main (int argc, char * argv [])
443 {
444 int c;
445
446 if(1 == argc) return PrintProcessList(FALSE);
447
448 while((c = getopt(argc, argv, "tl")) != -1)
449 {
450 switch(c)
451 {
452 case 't': return PrintProcessList(TRUE);
453 case 'l': return PrintLicense();
454 default: return PrintSynopsys(EXIT_FAILURE);
455 }
456 }
457
458 if(isdigit(argv[optind][0]))
459 return PrintProcess (argv[1]);
460
461 return PrintSynopsys(EXIT_SUCCESS);
462 }
463
464 /* EOF */