* autoload.cc: Add dynamic load statements for 'ZwQueryInformationProcess' and
'ZwQueryVirtualMemory'. * fhandler.h: Change type of bufalloc and filesize members of fhandler_virtual from int to size_t. Change type of position member from __off32_t to __off64_t. Add new fileid member to fhandler_virtual class. Make seekdir take an __off64_t argument. Make lseek take an __off64_t argument. Add fill_filebuf method to fhandler_virtual. Add fill_filebuf method to fhandler_proc. Add fill_filebuf method to fhandler_registry. Add fill_filebuf method to fhandler_process. Add saved_pid and saved_p members to fhandler_process. * fhandler_proc.cc (proc_listing_array): Add 'loadavg', 'meminfo', and 'stat'. (proc_fhandlers array): Ditto. (fhandler_proc::open): Use fill_filebuf to flesh out the file contents. (fhandler_proc::fill_filebuf): New method. (fhandler_proc::format_proc_meminfo): Ditto. (fhandler_proc::format_proc_stat): Ditto. (fhandler_proc::format_proc_uptime): Ditto. * fhandler_process.cc (process_listing): Add 'stat' and 'statm'. (fhandler_process::fstat): Find the _pinfo structure for the process named in the filename. Return ENOENT if the process is no longer around. Set the gid and uid fields of the stat structure. (fhandler_process::open): Store pid and pointer to _pinfo structure in saved_pid and saved_p respectively. Use fill_filebuf to flesh out file contents. (fhandler_proc::fill_filebuf): New method. (format_process_stat): New function. (format_process_status): Ditto. (format_process_statm): Ditto. (get_process_state): Ditto. (get_mem_values): Ditto. * fhandler_registry.cc (fhandler_registry::seekdir): Change argument type from __off32_t to __off64_t. (fhandler_registry::fill_filebuf): New method. * fhandler_virtual.cc (fhandler_virtual::seekdir): Change argument type from __off32_t to __off64_t. (fhandler_virtual::lseek): Ditto. (fhandler_virtual::fill_filebuf): New method. (fhandler_virtual::fhandler_virtual): Initialise fileid to -1. * wincap.cc: Set flag has_process_io_counters appropriately. * wincap.h: Add flag has_process_io_counters.
This commit is contained in:
@ -14,6 +14,7 @@ details. */
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/cygwin.h>
|
||||
#include <ntdef.h>
|
||||
#include "cygerrno.h"
|
||||
#include "security.h"
|
||||
#include "fhandler.h"
|
||||
@ -24,20 +25,27 @@ details. */
|
||||
#include "cygheap.h"
|
||||
#include <assert.h>
|
||||
#include <sys/utsname.h>
|
||||
#include "ntdll.h"
|
||||
|
||||
#define _COMPILING_NEWLIB
|
||||
#include <dirent.h>
|
||||
|
||||
/* offsets in proc_listing */
|
||||
static const int PROC_REGISTRY = 2; // /proc/registry
|
||||
static const int PROC_VERSION = 3; // /proc/version
|
||||
static const int PROC_UPTIME = 4; // /proc/uptime
|
||||
static const int PROC_LOADAVG = 2; // /proc/loadavg
|
||||
static const int PROC_MEMINFO = 3; // /proc/meminfo
|
||||
static const int PROC_REGISTRY = 4; // /proc/registry
|
||||
static const int PROC_STAT = 5; // /proc/stat
|
||||
static const int PROC_VERSION = 6; // /proc/version
|
||||
static const int PROC_UPTIME = 7; // /proc/uptime
|
||||
|
||||
/* names of objects in /proc */
|
||||
static const char *proc_listing[] = {
|
||||
".",
|
||||
"..",
|
||||
"loadavg",
|
||||
"meminfo",
|
||||
"registry",
|
||||
"stat",
|
||||
"version",
|
||||
"uptime",
|
||||
NULL
|
||||
@ -48,11 +56,14 @@ static const int PROC_LINK_COUNT = (sizeof(proc_listing) / sizeof(const char *))
|
||||
/* FH_PROC in the table below means the file/directory is handles by
|
||||
* fhandler_proc.
|
||||
*/
|
||||
static const DWORD proc_fhandlers[] = {
|
||||
static const DWORD proc_fhandlers[PROC_LINK_COUNT] = {
|
||||
FH_PROC,
|
||||
FH_PROC,
|
||||
FH_PROC,
|
||||
FH_PROC,
|
||||
FH_REGISTRY,
|
||||
FH_PROC,
|
||||
FH_PROC,
|
||||
FH_PROC
|
||||
};
|
||||
|
||||
@ -60,6 +71,10 @@ static const DWORD proc_fhandlers[] = {
|
||||
const char proc[] = "/proc";
|
||||
const int proc_len = sizeof (proc) - 1;
|
||||
|
||||
static off_t format_proc_meminfo (char *destbuf, size_t maxsize);
|
||||
static off_t format_proc_stat (char *destbuf, size_t maxsize);
|
||||
static off_t format_proc_uptime (char *destbuf, size_t maxsize);
|
||||
|
||||
/* auxillary function that returns the fhandler associated with the given path
|
||||
* this is where it would be nice to have pattern matching in C - polymorphism
|
||||
* just doesn't cut it
|
||||
@ -291,33 +306,9 @@ fhandler_proc::open (path_conv *pc, int flags, mode_t mode)
|
||||
res = 0;
|
||||
goto out;
|
||||
}
|
||||
switch (proc_file_no)
|
||||
{
|
||||
case PROC_VERSION:
|
||||
{
|
||||
struct utsname uts_name;
|
||||
uname (&uts_name);
|
||||
filesize = bufalloc = strlen (uts_name.sysname) + 1 +
|
||||
strlen (uts_name.release) + 1 + strlen (uts_name.version) + 2;
|
||||
filebuf = (char *) cmalloc (HEAP_BUF, bufalloc);
|
||||
__small_sprintf (filebuf, "%s %s %s\n", uts_name.sysname,
|
||||
uts_name.release, uts_name.version);
|
||||
break;
|
||||
}
|
||||
case PROC_UPTIME:
|
||||
{
|
||||
/* GetTickCount() wraps after 49 days - on WinNT/2000/XP, should use
|
||||
* perfomance counters but I don't know Redhat's policy on
|
||||
* NT only dependancies.
|
||||
*/
|
||||
DWORD ticks = GetTickCount ();
|
||||
filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 40);
|
||||
__small_sprintf (filebuf, "%d.%02d\n", ticks / 1000,
|
||||
(ticks / 10) % 100);
|
||||
filesize = strlen (filebuf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fileid = proc_file_no;
|
||||
fill_filebuf ();
|
||||
|
||||
if (flags & O_APPEND)
|
||||
position = filesize;
|
||||
@ -332,3 +323,197 @@ out:
|
||||
syscall_printf ("%d = fhandler_proc::open (%p, %d)", res, flags, mode);
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
fhandler_proc::fill_filebuf ()
|
||||
{
|
||||
switch (fileid)
|
||||
{
|
||||
case PROC_VERSION:
|
||||
{
|
||||
if (!filebuf)
|
||||
{
|
||||
struct utsname uts_name;
|
||||
uname (&uts_name);
|
||||
bufalloc = strlen (uts_name.sysname) + 1 + strlen (uts_name.release) +
|
||||
1 + strlen (uts_name.version) + 2;
|
||||
filebuf = (char *) cmalloc (HEAP_BUF, bufalloc);
|
||||
filesize = __small_sprintf (filebuf, "%s %s %s\n", uts_name.sysname,
|
||||
uts_name.release, uts_name.version);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PROC_UPTIME:
|
||||
{
|
||||
if (!filebuf)
|
||||
filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 80);
|
||||
filesize = format_proc_uptime (filebuf, bufalloc);
|
||||
break;
|
||||
}
|
||||
case PROC_STAT:
|
||||
{
|
||||
if (!filebuf)
|
||||
filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048);
|
||||
filesize = format_proc_stat (filebuf, bufalloc);
|
||||
break;
|
||||
}
|
||||
case PROC_LOADAVG:
|
||||
{
|
||||
/*
|
||||
* not really supported - Windows doesn't keep track of these values
|
||||
* Windows 95/98/me does have the KERNEL/CPUUsage performance counter
|
||||
* which is similar.
|
||||
*/
|
||||
if (!filebuf)
|
||||
filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 16);
|
||||
filesize = __small_sprintf (filebuf, "%u.%02u %u.%02u %u.%02u\n",
|
||||
0, 0, 0, 0, 0, 0);
|
||||
break;
|
||||
}
|
||||
case PROC_MEMINFO:
|
||||
{
|
||||
if (!filebuf)
|
||||
filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048);
|
||||
filesize = format_proc_meminfo (filebuf, bufalloc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
off_t
|
||||
format_proc_meminfo (char *destbuf, size_t maxsize)
|
||||
{
|
||||
unsigned long mem_total = 0UL, mem_free = 0UL, swap_total = 0UL,
|
||||
swap_free = 0UL;
|
||||
MEMORYSTATUS memory_status;
|
||||
GlobalMemoryStatus (&memory_status);
|
||||
mem_total = memory_status.dwTotalPhys;
|
||||
mem_free = memory_status.dwAvailPhys;
|
||||
swap_total = memory_status.dwTotalPageFile;
|
||||
swap_free = memory_status.dwAvailPageFile;
|
||||
return __small_sprintf (destbuf, " total: used: free:\n"
|
||||
"Mem: %10lu %10lu %10lu\n"
|
||||
"Swap: %10lu %10lu %10lu\n"
|
||||
"MemTotal: %10lu kB\n"
|
||||
"MemFree: %10lu kB\n"
|
||||
"MemShared: 0 kB\n"
|
||||
"HighTotal: 0 kB\n"
|
||||
"HighFree: 0 kB\n"
|
||||
"LowTotal: %10lu kB\n"
|
||||
"LowFree: %10lu kB\n"
|
||||
"SwapTotal: %10lu kB\n"
|
||||
"SwapFree: %10lu kB\n",
|
||||
mem_total, mem_total - mem_free, mem_free,
|
||||
swap_total, swap_total - swap_free, swap_free,
|
||||
mem_total >> 10, mem_free >> 10,
|
||||
mem_total >> 10, mem_free >> 10,
|
||||
swap_total >> 10, swap_free >> 10);
|
||||
}
|
||||
|
||||
static
|
||||
off_t
|
||||
format_proc_uptime (char *destbuf, size_t maxsize)
|
||||
{
|
||||
unsigned long long uptime = 0ULL, idle_time = 0ULL;
|
||||
SYSTEM_PROCESSOR_TIMES spt;
|
||||
|
||||
NTSTATUS ret = ZwQuerySystemInformation (SystemProcessorTimes, (PVOID) &spt,
|
||||
sizeof spt, NULL);
|
||||
if (!ret && GetLastError () == ERROR_PROC_NOT_FOUND)
|
||||
uptime = GetTickCount() / 10;
|
||||
else if (ret != STATUS_SUCCESS)
|
||||
{
|
||||
__seterrno_from_win_error (RtlNtStatusToDosError (ret));
|
||||
debug_printf("NtQuerySystemInformation: ret = %d, "
|
||||
"Dos(ret) = %d",
|
||||
ret, RtlNtStatusToDosError (ret));
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
idle_time = spt.IdleTime.QuadPart / 100000ULL;
|
||||
uptime = (spt.InterruptTime.QuadPart + spt.KernelTime.QuadPart +
|
||||
spt.IdleTime.QuadPart + spt.UserTime.QuadPart +
|
||||
spt.DpcTime.QuadPart) / 100000ULL;
|
||||
}
|
||||
|
||||
return __small_sprintf (destbuf, "%U.%02u %U.%02u\n",
|
||||
uptime / 100, long (uptime % 100),
|
||||
idle_time / 100, long (idle_time % 100));
|
||||
}
|
||||
|
||||
static
|
||||
off_t
|
||||
format_proc_stat (char *destbuf, size_t maxsize)
|
||||
{
|
||||
unsigned long long user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL;
|
||||
unsigned long pages_in = 0UL, pages_out = 0UL, interrupt_count = 0UL,
|
||||
context_switches = 0UL, swap_in = 0UL, swap_out = 0UL;
|
||||
time_t boot_time = 0;
|
||||
|
||||
if (wincap.is_winnt ())
|
||||
{
|
||||
NTSTATUS ret;
|
||||
SYSTEM_PROCESSOR_TIMES spt;
|
||||
SYSTEM_PERFORMANCE_INFORMATION spi;
|
||||
SYSTEM_TIME_OF_DAY_INFORMATION stodi;
|
||||
ret = ZwQuerySystemInformation (SystemProcessorTimes,
|
||||
(PVOID) &spt,
|
||||
sizeof spt, NULL);
|
||||
if (ret == STATUS_SUCCESS)
|
||||
ret = ZwQuerySystemInformation (SystemPerformanceInformation,
|
||||
(PVOID) &spi,
|
||||
sizeof spi, NULL);
|
||||
if (ret == STATUS_SUCCESS)
|
||||
ret = ZwQuerySystemInformation (SystemTimeOfDayInformation,
|
||||
(PVOID) &stodi,
|
||||
sizeof stodi, NULL);
|
||||
if (ret != STATUS_SUCCESS)
|
||||
{
|
||||
__seterrno_from_win_error (RtlNtStatusToDosError (ret));
|
||||
debug_printf("NtQuerySystemInformation: ret = %d, "
|
||||
"Dos(ret) = %d",
|
||||
ret, RtlNtStatusToDosError (ret));
|
||||
return 0;
|
||||
}
|
||||
kernel_time = (spt.KernelTime.QuadPart + spt.InterruptTime.QuadPart + spt.DpcTime.QuadPart) / 100000ULL;
|
||||
user_time = spt.UserTime.QuadPart / 100000ULL;
|
||||
idle_time = spt.IdleTime.QuadPart / 100000ULL;
|
||||
interrupt_count = spt.InterruptCount;
|
||||
pages_in = spi.PagesRead;
|
||||
pages_out = spi.PagefilePagesWritten + spi.MappedFilePagesWritten;
|
||||
/*
|
||||
* Note: there is no distinction made in this structure between pages
|
||||
* read from the page file and pages read from mapped files, but there
|
||||
* is such a distinction made when it comes to writing. Goodness knows
|
||||
* why. The value of swap_in, then, will obviously be wrong but its our
|
||||
* best guess.
|
||||
*/
|
||||
swap_in = spi.PagesRead;
|
||||
swap_out = spi.PagefilePagesWritten;
|
||||
context_switches = spi.ContextSwitches;
|
||||
boot_time = to_time_t ((FILETIME *) &stodi.BootTime.QuadPart);
|
||||
}
|
||||
/*
|
||||
* else
|
||||
* {
|
||||
* There are only two relevant performance counters on Windows 95/98/me,
|
||||
* VMM/cPageIns and VMM/cPageOuts. The extra effort needed to read these
|
||||
* counters is by no means worth it.
|
||||
* }
|
||||
*/
|
||||
return __small_sprintf (destbuf, "cpu %U %U %U %U\n"
|
||||
"page %u %u\n"
|
||||
"swap %u %u\n"
|
||||
"intr %u\n"
|
||||
"ctxt %u\n"
|
||||
"btime %u\n",
|
||||
user_time, 0ULL,
|
||||
kernel_time, idle_time,
|
||||
pages_in, pages_out,
|
||||
swap_in, swap_out,
|
||||
interrupt_count,
|
||||
context_switches,
|
||||
boot_time);
|
||||
}
|
||||
|
Reference in New Issue
Block a user