From e0308e50e81199752cb9f26b15d57978c9f629b3 Mon Sep 17 00:00:00 2001 From: Emanuele Aliberti Date: Sun, 4 Nov 2001 21:53:20 +0000 Subject: [PATCH] tlist clone (partial). 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 | 69 +++++ rosapps/sysutils/tlist/tlist.c | 495 ++++++++++++++++++++++++++++++++ rosapps/sysutils/tlist/tlist.rc | 37 +++ 3 files changed, 601 insertions(+) create mode 100644 rosapps/sysutils/tlist/Makefile create mode 100644 rosapps/sysutils/tlist/tlist.c create mode 100644 rosapps/sysutils/tlist/tlist.rc diff --git a/rosapps/sysutils/tlist/Makefile b/rosapps/sysutils/tlist/Makefile new file mode 100644 index 00000000000..0d9b5da8bba --- /dev/null +++ b/rosapps/sysutils/tlist/Makefile @@ -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 index 00000000000..4cd72d6fad4 --- /dev/null +++ b/rosapps/sysutils/tlist/tlist.c @@ -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 +#define NTOS_MODE_USER +#include + +#include +#include +#include +#include + +#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 index 00000000000..b3a825e4052 --- /dev/null +++ b/rosapps/sysutils/tlist/tlist.rc @@ -0,0 +1,37 @@ +#include +#include + +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