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