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   &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  SIZE_T nSize = 0;
62 
63  NtFreeVirtualMemory(NtCurrentProcess(), &ptr, &nSize, MEM_RELEASE);
64 }
65 
66 int WINAPI PrintBanner (VOID)
67 {
68   printf ("ReactOS "KERNEL_VERSION_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 != HandleToUlong(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     HandleToUlong(pInfo->UniqueProcessId),
162     HandleToUlong(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 = UlongToHandle(ALREADY_PROCESSED);
181   /* Save current process' PID */
182   Pid = pInfo->UniqueProcessId;
183   /* Scan and print possible children */
184   do {
185 
186     if (ALREADY_PROCESSED != HandleToUlong(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 = UlongToHandle(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 (%04d)\n",
231 	  HandleToUlong(pInfo->UniqueProcessId),
232 	  Module,
233 	  Title,
234 	  HandleToUlong(pInfo->InheritedFromUniqueProcessId)
235 	  );
236       }
237       else
238       {
239 	if (ALREADY_PROCESSED != HandleToUlong(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%p LastErr:0x%08x State:%s\n",
314       HandleToUlong(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 = UlongToHandle(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", HandleToUlong(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 */
465