tlist clone (partial).
authorEmanuele Aliberti <ea@iol.it>
Sun, 4 Nov 2001 21:53:20 +0000 (21:53 +0000)
committerEmanuele Aliberti <ea@iol.it>
Sun, 4 Nov 2001 21:53:20 +0000 (21:53 +0000)
Tested under NT 4.0.1382 SP6a EN_US.
NOT tested under ROS, but it should NOT work, since
NtQuerySystemInformation misses at least one info class needed
by the application.

svn path=/trunk/; revision=2352

rosapps/sysutils/tlist/Makefile [new file with mode: 0644]
rosapps/sysutils/tlist/tlist.c [new file with mode: 0644]
rosapps/sysutils/tlist/tlist.rc [new file with mode: 0644]

diff --git a/rosapps/sysutils/tlist/Makefile b/rosapps/sysutils/tlist/Makefile
new file mode 100644 (file)
index 0000000..0d9b5da
--- /dev/null
@@ -0,0 +1,69 @@
+# $Id: Makefile,v 1.1 2001/11/04 21:53:20 ea Exp $
+#
+#  ReactOS makefile for TList
+#
+PATH_TO_TOP=../..
+
+include $(PATH_TO_TOP)/rules.mak
+
+TARGET_NAME=tlist
+
+all: $(TARGET_NAME)$(EXE_POSTFIX)
+
+ROS_DIR=../$(PATH_TO_TOP)/reactos
+ROS_INC=$(ROS_DIR)/include
+ROS_LIB=$(ROS_DIR)/dk/w32/lib
+IMPORT_NTDLL=$(ROS_LIB)/ntdll.a
+IMPORT_KERNEL32=$(ROS_LIB)/kernel32.a
+IMPORT_CRTDLL=$(ROS_LIB)/msvcrt.a
+
+
+BASE_CFLAGS=-I$(ROS_INC)
+
+OBJECTS = \
+       tlist.o \
+       $(TARGET_NAME).coff
+
+CLEAN_FILES = \
+       *.o                             \
+       $(TARGET_NAME)$(EXE_POSTFIX)    \
+       $(TARGET_NAME).sym              \
+       $(TARGET_NAME).coff
+
+$(TARGET_NAME)$(EXE_POSTFIX): $(OBJECTS)
+       $(CC) \
+               -Wl,--subsystem,console \
+               -o $@                   \
+               $(OBJECTS)              \
+               $(IMPORT_NTDLL)
+       $(NM) --numeric-sort $(TARGET_NAME)$(EXE_POSTFIX) > $(TARGET_NAME).sym
+
+clean: $(CLEAN_FILES:%=%_clean)
+
+$(CLEAN_FILES:%=%_clean): %_clean:
+       - $(RM) $*
+
+.phony: clean $(CLEAN_FILES:%=%_clean)
+
+
+floppy: $(TARGET:%=$(FLOPPY_DIR)/apps/%)
+
+$(TARGET:%=$(FLOPPY_DIR)/apps/%): $(FLOPPY_DIR)/apps/%: %
+ifeq ($(DOSCLI),yes)
+       $(CP) $* $(FLOPPY_DIR)\apps\$*
+else
+       $(CP) $* $(FLOPPY_DIR)/apps/$*
+endif
+
+
+dist: $(TARGET:%=../$(DIST_DIR)/apps/%)
+
+$(TARGET:%=../$(DIST_DIR)/apps/%): ../$(DIST_DIR)/apps/%: %
+ifeq ($(DOSCLI),yes)
+       $(CP) $* ..\$(DIST_DIR)\apps\$*
+else
+       $(CP) $* ../$(DIST_DIR)/apps\$*
+endif
+
+# EOF
+
diff --git a/rosapps/sysutils/tlist/tlist.c b/rosapps/sysutils/tlist/tlist.c
new file mode 100644 (file)
index 0000000..4cd72d6
--- /dev/null
@@ -0,0 +1,495 @@
+/* $Id: tlist.c,v 1.1 2001/11/04 21:53:20 ea Exp $
+ *
+ * ReactOS Project
+ * TList
+ *
+ * Copyright (c) 2000,2001 Emanuele Aliberti
+ */
+#include <reactos/buildno.h>
+#define NTOS_MODE_USER
+#include <ntos.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+#define ALREADY_PROCESSED ((DWORD)-1)
+
+LPWSTR ThreadStateName [] =
+{
+  L"Initialized",
+  L"Ready",
+  L"Running",
+  L"Standby",
+  L"Terminated",
+  L"Wait",
+  L"Transition",
+  L"Unknown",
+  NULL
+};
+
+
+
+int STDCALL PrintBanner (VOID)
+{
+  printf ("ReactOS "KERNEL_RELEASE_STR" T(ask)List\n");
+  printf ("Copyright (c) 2000,2001 Emanuele Aliberti\n\n");
+  return EXIT_SUCCESS;
+}
+
+int STDCALL PrintSynopsys (VOID)
+{
+  PrintBanner ();
+  printf ("Usage: tlist [-t | PID | -l]\n\n"
+          "  -t   print the task list tree\n"
+          "  PID  print module information for this ID\n"
+          "  -l   print license information\n");
+  return EXIT_SUCCESS;
+}
+
+int STDCALL PrintLicense (VOID)
+{
+  PrintBanner ();
+  printf (
+"This program is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU General Public License as published by\n"
+"the Free Software Foundation; either version 2 of the License, or\n"
+"(at your option) any later version.\n\n");
+  printf (
+"This program is distributed in the hope that it will be useful,\n"
+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
+"GNU General Public License for more details.\n\n");
+  printf (
+"You should have received a copy of the GNU General Public License\n"
+"along with this program; if not, write to the Free Software\n"
+"Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
+  return EXIT_SUCCESS;
+}
+
+BOOL STDCALL AcquirePrivileges (VOID)
+{
+  /* TODO: implement it */
+  return TRUE;
+}
+
+PSYSTEM_PROCESS_INFORMATION STDCALL
+GetProcessAndThreadsInfo (PULONG Size)
+{
+  NTSTATUS                    Status = STATUS_SUCCESS;
+  PSYSTEM_PROCESS_INFORMATION pInfo = NULL;
+  ULONG                       Length = PAGE_SIZE;
+  ULONG                       RequiredLength = 0;
+
+  while (TRUE)
+  {
+    Status = NtAllocateVirtualMemory (
+               NtCurrentProcess(),
+              (PVOID) & pInfo,
+              0,
+              & Length,
+              (MEM_RESERVE | MEM_COMMIT),
+              PAGE_READWRITE
+              );
+    if (!NT_SUCCESS(Status) || (NULL == pInfo))
+    {
+      fprintf (stderr, "%s(%d): Status = 0x%08lx\n",__FUNCTION__,__LINE__,Status);
+      return NULL;
+    }
+    /*
+     * Obtain required buffer size (well, try to...)
+     */
+    if (NtQuerySystemInformation (
+          SystemProcessesAndThreadsInformation,
+          pInfo,
+          Length,
+         & RequiredLength
+         ) != STATUS_INFO_LENGTH_MISMATCH)
+    {
+      break;
+    }
+    NtFreeVirtualMemory (NtCurrentProcess(), (PVOID)&pInfo, & Length, MEM_RELEASE);
+    Length += PAGE_SIZE;
+  }
+  if (!NT_SUCCESS(Status))
+  {
+    NtFreeVirtualMemory (NtCurrentProcess(), (PVOID)&pInfo, & Length, MEM_RELEASE);
+    return NULL;
+  }
+  if (NULL != Size)
+  {
+    *Size = Length;
+  }
+  return pInfo;
+}
+
+int STDCALL
+ProcessHasDescendants (
+  ULONG                       Pid,
+  PSYSTEM_PROCESS_INFORMATION pInfo
+  )
+{
+  LONG Count = 0;
+
+  if (NULL == pInfo) return 0;
+  do {
+
+      if (ALREADY_PROCESSED != pInfo->ParentProcessId)
+      {
+        if ((Pid != pInfo->ProcessId) && (Pid == pInfo->ParentProcessId))
+        {
+          ++ Count;
+        }
+      }
+      (PBYTE) pInfo += pInfo->RelativeOffset;
+
+  } while (0 != pInfo->RelativeOffset);
+
+  return Count;
+}
+
+
+BOOL STDCALL
+GetProcessInfo (
+  PSYSTEM_PROCESS_INFORMATION pInfo,
+  LPWSTR                      * Module,
+  LPWSTR                      * Title
+  )
+{
+      *Module = (pInfo->Name.Length ? pInfo->Name.Buffer : L"System process");
+      *Title = L""; /* TODO: check if the process has any window */
+      return TRUE;
+}
+
+int STDCALL PrintProcessInfoDepth (
+  PSYSTEM_PROCESS_INFORMATION pInfo,
+  LONG                        Depth
+  )
+{
+  INT     d = 0;
+  LPWSTR  Module = L"";
+  LPWSTR  Title = L"";
+  
+  for (d = 0; d < Depth; d ++) printf ("  ");
+  GetProcessInfo (pInfo, & Module, & Title);
+  wprintf (
+    L"%s (%d, %d) %s\n",
+    Module,
+    pInfo->ProcessId,
+    pInfo->ParentProcessId,
+    Title
+    );
+  return EXIT_SUCCESS;
+}
+
+int STDCALL
+PrintProcessAndDescendants (
+  PSYSTEM_PROCESS_INFORMATION pInfo,
+  PSYSTEM_PROCESS_INFORMATION pInfoBase,
+  LONG                        Depth
+  )
+{
+  DWORD   Pid = 0;
+
+  if (NULL == pInfo) return EXIT_FAILURE;
+  /* Print current pInfo process */
+  PrintProcessInfoDepth (pInfo, Depth ++);
+  pInfo->ParentProcessId = ALREADY_PROCESSED;
+  /* Save current process' PID */
+  Pid = pInfo->ProcessId;
+  /* Scan and print possible children */
+  do {
+
+    if (ALREADY_PROCESSED != pInfo->ParentProcessId)
+    {
+      if (Pid == pInfo->ParentProcessId)
+      {
+        if (ProcessHasDescendants (Pid, pInfoBase))
+        {
+          PrintProcessAndDescendants (
+            pInfo,
+            pInfoBase,
+            Depth
+            );
+        }
+       else
+       {
+          PrintProcessInfoDepth (pInfo, Depth);
+         pInfo->ParentProcessId = ALREADY_PROCESSED;
+       }
+      }
+    }
+    (PBYTE) pInfo += pInfo->RelativeOffset;
+
+  } while (0 != pInfo->RelativeOffset);
+  
+  return EXIT_SUCCESS;
+}
+
+int STDCALL PrintProcessList (BOOL DisplayTree)
+{
+  PSYSTEM_PROCESS_INFORMATION pInfo = NULL;
+  PSYSTEM_PROCESS_INFORMATION pInfoBase = NULL;
+  LONG                        Length = 0;
+  LPWSTR                      Module = L"";
+  LPWSTR                      Title = L"";
+
+  
+  pInfo = GetProcessAndThreadsInfo (& Length);
+  if (NULL == pInfo) return EXIT_FAILURE;
+  pInfoBase = pInfo;
+  do {
+      if (FALSE == DisplayTree)
+      {
+        GetProcessInfo (pInfo, & Module, & Title);
+        wprintf (
+          L"%4d %-16s %s\n",
+         pInfo->ProcessId,
+         Module,
+         Title,
+         pInfo->ParentProcessId
+         );
+      }
+      else 
+      {
+       if (ALREADY_PROCESSED != pInfo->ParentProcessId)
+       {
+         PrintProcessAndDescendants (pInfo, pInfoBase, 0);
+       }
+      }
+      (PBYTE) pInfo += pInfo->RelativeOffset;
+
+    } while (0 != pInfo->RelativeOffset);
+  
+    NtFreeVirtualMemory (
+      NtCurrentProcess(),
+      (PVOID) & pInfoBase,
+      & Length,
+      MEM_RELEASE
+      );
+  
+    return EXIT_SUCCESS;
+}
+
+
+int STDCALL PrintThreads (PSYSTEM_PROCESS_INFORMATION pInfo)
+{
+  ULONG                    ThreadIndex = 0;
+  NTSTATUS                 Status = STATUS_SUCCESS;
+  HANDLE                   hThread = INVALID_HANDLE_VALUE;
+  OBJECT_ATTRIBUTES        Oa = {0};
+  PVOID                    Win32StartAddress = NULL;
+  THREAD_BASIC_INFORMATION tInfo = {0};
+  ULONG                    ReturnLength = 0;
+
+  if (NULL == pInfo) return EXIT_FAILURE;
+
+  wprintf (L"   NumberOfThreads: %d\n", pInfo->ThreadCount);
+
+  for (ThreadIndex = 0; ThreadIndex < pInfo->ThreadCount; ThreadIndex ++)
+  {
+    Status = NtOpenThread (
+              & hThread,
+              THREAD_QUERY_INFORMATION,
+              & Oa,
+              & pInfo->ThreadSysInfo[ThreadIndex].ClientId
+               );
+    if (!NT_SUCCESS(Status))
+    {
+      continue;
+    }
+    
+    Status = NtQueryInformationThread (
+               hThread,
+              ThreadBasicInformation,
+              (PVOID) & tInfo,
+              sizeof tInfo,
+              & ReturnLength
+               );
+    if (!NT_SUCCESS(Status))
+    {
+      NtClose (hThread);
+      continue;
+    }
+
+    Status = NtQueryInformationThread (
+               hThread,
+              ThreadQuerySetWin32StartAddress,
+              (PVOID) & Win32StartAddress,
+              sizeof Win32StartAddress,
+              & ReturnLength
+               );
+    if (!NT_SUCCESS(Status))
+    {
+      NtClose (hThread);
+      continue;
+    }
+    
+    NtClose (hThread);
+
+    /* Now print the collected information */
+    wprintf (L"   %4d Win32StartAddr:0x%08x LastErr:0x%08x State:%s\n",
+      pInfo->ThreadSysInfo[ThreadIndex].ClientId.UniqueThread,
+      Win32StartAddress,
+      0 /* FIXME: ((PTEB) tInfo.TebBaseAddress)->LastErrorValue */,
+      ThreadStateName[pInfo->ThreadSysInfo[ThreadIndex].State]
+      );
+  } 
+  return EXIT_SUCCESS;
+}
+
+int STDCALL PrintModules (VOID)
+{
+       /* TODO */
+       return EXIT_SUCCESS;
+}
+
+PSYSTEM_PROCESS_INFORMATION STDCALL
+GetProcessInfoPid (
+  PSYSTEM_PROCESS_INFORMATION pInfoBase,
+  DWORD                       Pid
+  )
+{
+  if (NULL == pInfoBase) return NULL;
+  do {
+
+    if (Pid == pInfoBase->ProcessId)
+    {
+      return pInfoBase;
+    }
+    (PBYTE) pInfoBase += pInfoBase->RelativeOffset;
+
+  } while (0 != pInfoBase->RelativeOffset);
+
+  return NULL;
+}
+
+int STDCALL PrintProcess (char * PidStr)
+{
+  NTSTATUS                    Status = 0;
+  HANDLE                      hProcess = 0;
+  OBJECT_ATTRIBUTES           Oa = {0};
+  CLIENT_ID                   ClientId = {0, 0};
+
+  
+  ClientId.UniqueProcess = (PVOID) atol (PidStr);
+  if (FALSE == AcquirePrivileges ())
+  {
+    return EXIT_FAILURE;
+  }
+  
+  Status = NtOpenProcess (
+             & hProcess,
+             PROCESS_QUERY_INFORMATION,
+             & Oa,
+             & ClientId
+             );
+  if (NT_SUCCESS(Status))
+  {
+    ULONG                       ReturnLength = 0;
+    PROCESS_BASIC_INFORMATION   PsBasic;
+    VM_COUNTERS                 PsVm;
+    PSYSTEM_PROCESS_INFORMATION pInfo = NULL;
+    PSYSTEM_PROCESS_INFORMATION pInfoBase = NULL;
+    LONG                        pInfoBaseLength = 0;
+    LPWSTR                      Module = L"";
+    LPWSTR                      Title = L"";
+    
+    Status = NtQueryInformationProcess (
+               hProcess,
+              ProcessBasicInformation,
+              & PsBasic,
+              sizeof (PsBasic),
+              & ReturnLength
+               );
+    if (!NT_SUCCESS(Status))
+    {
+      return EXIT_FAILURE;
+    }
+    Status = NtQueryInformationProcess (
+               hProcess,
+              ProcessVmCounters,
+              & PsVm,
+              sizeof (PsVm),
+              & ReturnLength
+               );
+    if (!NT_SUCCESS(Status))
+    {
+      return EXIT_FAILURE;
+    }
+
+    pInfoBase = GetProcessAndThreadsInfo (& pInfoBaseLength);
+    if (NULL == pInfoBase) return EXIT_FAILURE;
+
+    pInfo = GetProcessInfoPid (pInfoBase, (DWORD) ClientId.UniqueProcess);
+    if (NULL == pInfo) return EXIT_FAILURE;
+
+    GetProcessInfo (pInfo, & Module, & Title);
+    
+    wprintf (L"%4d %s\n", ClientId.UniqueProcess, Module);
+#if 0
+    printf ("   CWD:     %s\n", ""); /* it won't appear if empty */
+    printf ("   CmdLine: %s\n", ""); /* it won't appear if empty */
+#endif
+    printf ("   VirtualSize:     %5ld kb   PeakVirtualSize:     %5ld kb\n",
+      ((LONG) PsVm.VirtualSize / 1024),
+      ((LONG) PsVm.PeakVirtualSize / 1024)
+      );
+    printf ("   WorkingSetSize:  %5ld kb   PeakWorkingSetSize:  %5ld kb\n",
+      ((LONG) PsVm.WorkingSetSize / 1024),
+      ((LONG) PsVm.PeakWorkingSetSize / 1024)
+      );
+    
+    PrintThreads (pInfo);
+
+    PrintModules ();
+    
+    NtFreeVirtualMemory (
+      NtCurrentProcess(),
+      (PVOID) & pInfoBase,
+      & pInfoBaseLength,
+      MEM_RELEASE
+      );
+  
+    NtClose (hProcess);
+    
+    return EXIT_SUCCESS;
+  }
+  return EXIT_FAILURE;
+}
+
+
+int main (int argc, char * argv [])
+{
+  if (1 == argc)
+  {
+    return PrintProcessList (FALSE);
+  }
+  if (2 == argc)
+  {
+    if (('-' == argv [1][0]) && ('\0' == argv [1][2]))
+    {
+      if ('t' == argv [1][1])
+      {
+        return PrintProcessList (TRUE);
+      }
+      if ('l' == argv [1][1])
+      {
+        return PrintLicense ();
+      }
+    }
+    if (isdigit(argv[1][0]))
+    {
+      return PrintProcess (argv[1]);
+    }
+  }
+  return PrintSynopsys ();
+}
+
+/* EOF */
diff --git a/rosapps/sysutils/tlist/tlist.rc b/rosapps/sysutils/tlist/tlist.rc
new file mode 100644 (file)
index 0000000..b3a825e
--- /dev/null
@@ -0,0 +1,37 @@
+#include <defines.h>
+#include <reactos/resource.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+       FILEVERSION     RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
+       PRODUCTVERSION  RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD      
+       FILEFLAGSMASK   0x3fL
+#ifdef _DEBUG
+       FILEFLAGS       0x1L
+#else
+       FILEFLAGS       0x0L
+#endif
+       FILEOS          0x40004L
+       FILETYPE        0x2L
+       FILESUBTYPE     0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName",       RES_STR_COMPANY_NAME
+            VALUE "FileDescription",   "ReactOS W32 T(ask)List\0"
+            VALUE "FileVersion",       RES_STR_FILE_VERSION
+            VALUE "InternalName",      "tlist\0"
+            VALUE "LegalCopyright",    "2000,2001 Emanuele Aliberti\0"
+            VALUE "OriginalFilename",  "tlist.exe\0"
+            VALUE "ProductName",       RES_STR_PRODUCT_NAME
+            VALUE "ProductVersion",    RES_STR_PRODUCT_VERSION
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END