/*
Adapted from ps.cc by J Robert Ray <jrray@jrray.org>
ps.cc
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <stdlib.h>
#include <tlhelp32.h>
#include <psapi.h>
#ifdef USE_CYGWIN
#include <getopt.h>
#include <unistd.h>
#include <pwd.h>
#include <sys/cygwin.h>
#else
/* MinGW32 sddl.h requires WINVER >= 0x0500 for ConvertSidToStringSidA prototype */
#if defined(WINVER) && WINVER < 0x0500
#undef WINVER
#endif
#ifndef WINVER
#define WINVER 0x0500
#endif
#include <sddl.h>
#endif
#include "os/MSWin32.h"
#ifdef USE_CYGWIN
typedef DWORD (WINAPI *GETMODULEFILENAME)(
HANDLE hProcess,
HMODULE hModule,
LPTSTR lpstrFileName,
DWORD nSize
);
#endif
typedef HANDLE (WINAPI *CREATESNAPSHOT)(
DWORD dwFlags,
DWORD th32ProcessID
);
typedef BOOL (WINAPI *PROCESSWALK)(
HANDLE hSnapshot,
LPPROCESSENTRY32 lppe
);
#ifdef USE_CYGWIN
typedef struct external_pinfo external_pinfo;
GETMODULEFILENAME myGetModuleFileNameEx;
#endif
CREATESNAPSHOT myCreateToolhelp32Snapshot;
PROCESSWALK myProcess32First;
PROCESSWALK myProcess32Next;
static int init_win_result = FALSE;
extern void bless_into_proc(char* , char**, ...);
#ifdef USE_CYGWIN
// Win95 functions
static DWORD WINAPI GetModuleFileNameEx95 (
HANDLE hProcess,
HMODULE hModule,
LPTSTR lpstrFileName,
DWORD n
)
{
HANDLE h;
DWORD pid = (DWORD) hModule;
PROCESSENTRY32 proc;
h = myCreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
if (!h)
return 0;
proc.dwSize = sizeof (proc);
if (myProcess32First(h, &proc))
do
if (proc.th32ProcessID == pid)
{
CloseHandle (h);
strcpy (lpstrFileName, proc.szExeFile);
return 1;
}
while (myProcess32Next (h, &proc));
CloseHandle (h);
return 0;
}
#endif
int
init_win ()
{
HMODULE h;
#ifdef USE_CYGWIN
OSVERSIONINFO os_version_info;
memset (&os_version_info, 0, sizeof os_version_info);
os_version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
GetVersionEx (&os_version_info);
if (os_version_info.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
h = LoadLibrary ("psapi.dll");
if (!h)
return 0;
myGetModuleFileNameEx = (GETMODULEFILENAME) GetProcAddress (h, "GetModuleFileNameExA");
if (!myGetModuleFileNameEx)
return 0;
return 1;
}
#endif
h = GetModuleHandle("KERNEL32.DLL");
myCreateToolhelp32Snapshot = (CREATESNAPSHOT)GetProcAddress (h, "CreateToolhelp32Snapshot");
myProcess32First = (PROCESSWALK)GetProcAddress (h, "Process32First");
myProcess32Next = (PROCESSWALK)GetProcAddress (h, "Process32Next");
if (!myCreateToolhelp32Snapshot || !myProcess32First || !myProcess32Next)
return 0;
#ifdef USE_CYGWIN
myGetModuleFileNameEx = GetModuleFileNameEx95;
#endif
return 1;
}
#define FACTOR (0x19db1ded53ea710LL)
#define NSPERSEC 10000000LL
/* Convert a Win32 time to "UNIX" format. */
static long
to_time_t (FILETIME *ptr)
{
/* A file time is the number of 100ns since jan 1 1601
stuffed into two long words.
A time_t is the number of seconds since jan 1 1970. */
long rem;
long long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned)ptr->dwLowDateTime);
x -= FACTOR; /* number of 100ns between 1601 and 1970 */
rem = x % ((long long)NSPERSEC);
rem += (NSPERSEC / 2);
x /= (long long) NSPERSEC; /* number of 100ns in a second */
x += (long long) (rem / NSPERSEC);
return x;
}
#ifdef USE_CYGWIN
void
OS_get_table()
{
external_pinfo *p;
int uid;
cygwin_getinfo_types query = CW_GETPINFO;
char ch;
int pid;
char *pstate;
char pname[MAX_PATH];
char uname[128];
char *fields;
uid = getuid ();
(void) cygwin_internal (CW_LOCK_PINFO, 1000);
if (query == CW_GETPINFO && !init_win_result)
query = CW_GETPINFO;
for (pid = 0;
(p = (external_pinfo *) cygwin_internal (query, pid | CW_NEXTPID));
pid = p->pid)
{
pstate = " ";
if (p->process_state & PID_STOPPED)
pstate = "stopped";
else if (p->process_state & PID_TTYIN)
pstate = "ttyin";
else if (p->process_state & PID_TTYOU)
pstate = "ttyout";
#ifdef PID_ORPHANED
if (p->process_state & (PID_ORPHANED | PID_EXITED))
#else
if (p->process_state & PID_EXITED)
#endif
strcpy (pname, "<defunct>");
else if (p->ppid)
{
char *s;
pname[0] = '\0';
cygwin_conv_path((CCP_RELATIVE|CCP_WIN_A_TO_POSIX), p->progname, pname, PATH_MAX);
s = strchr (pname, '\0') - 4;
if (s > pname && strcasecmp (s, ".exe") == 0)
*s = '\0';
}
else if (query == CW_GETPINFO)
{
FILETIME ct, et, kt, ut;
HANDLE h = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, p->dwProcessId);
if (!h)
continue;
if (!myGetModuleFileNameEx (h, myProcess32First ? p->dwProcessId : NULL, pname, MAX_PATH))
strcpy (pname, "*** unknown ***");
if (GetProcessTimes (h, &ct, &et, &kt, &ut))
p->start_time = to_time_t (&ct);
CloseHandle (h);
}
{
struct passwd *pw;
if ((pw = getpwuid (p->version >= EXTERNAL_PINFO_VERSION_32_BIT ?
p->uid32 : p->uid)))
strcpy (uname, pw->pw_name);
else
sprintf (uname, "%u", (unsigned)
(p->version >= EXTERNAL_PINFO_VERSION_32_BIT ?
p->uid32 : p->uid));
}
if (query == CW_GETPINFO) {
fields = "iiiiisiis";
} else {
fields = "iiiiisIis";
}
bless_into_proc(fields, Fields,
p->version >= EXTERNAL_PINFO_VERSION_32_BIT ? p->uid32 : p->uid,
p->pid,
p->ppid,
p->pgid,
p->dwProcessId,
pname,
p->start_time,
p->ctty,
pstate
);
}
(void) cygwin_internal (CW_UNLOCK_PINFO);
}
#else
static void get_process_owner(HANDLE process, char string_sid[184], char user_name[256], char domain_name[255])
{
HANDLE process_token;
PTOKEN_USER token_user;
DWORD token_user_size;
char *string_sid_ptr;
size_t string_sid_len;
DWORD user_name_size;
DWORD domain_name_size;
SID_NAME_USE sid_type;
string_sid[0] = 0;
user_name[0] = 0;
domain_name[0] = 0;
if (!OpenProcessToken (process, TOKEN_QUERY, &process_token))
return;
if (!GetTokenInformation (process_token, TokenUser, NULL, 0, &token_user_size) && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
{
CloseHandle (process_token);
return;
}
token_user = malloc (token_user_size);
if (!token_user)
{
CloseHandle (process_token);
return;
}
if (!GetTokenInformation (process_token, TokenUser, token_user, token_user_size, &token_user_size))
{
free (token_user);
CloseHandle (process_token);
return;
}
if (ConvertSidToStringSidA (token_user->User.Sid, &string_sid_ptr))
{
string_sid_len = strlen (string_sid_ptr);
if (string_sid_len < 184)
memcpy (string_sid, string_sid_ptr, string_sid_len+1);
LocalFree (string_sid_ptr);
}
user_name_size = 256;
domain_name_size = 256;
if (!LookupAccountSidA (NULL, token_user->User.Sid, user_name, &user_name_size, domain_name, &domain_name_size, &sid_type) && GetLastError () == ERROR_NONE_MAPPED)
{
strcpy (user_name, "NONE_MAPPED");
strcpy (domain_name, "NONE_MAPPED");
}
free (token_user);
CloseHandle (process_token);
}
static unsigned long get_uid_from_string_sid(char *string_sid)
{
char *uid_ptr;
char *ptr;
uid_ptr = strrchr (string_sid, '-');
if (!uid_ptr)
return 0;
uid_ptr++;
for (ptr = uid_ptr; *ptr; ptr++)
if (*ptr < '0' || *ptr > '9')
return 0;
return strtoul (uid_ptr, NULL, 10);
}
void
OS_get_table()
{
HANDLE proc;
HANDLE snapshot;
PROCESSENTRY32 proc_entry;
FILETIME ct, et, kt, ut;
char string_sid[184];
char user_name[256];
char domain_name[256];
unsigned long uid;
long start_time;
if (!init_win_result)
return;
snapshot = myCreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
if (!snapshot)
return;
proc_entry.dwSize = sizeof (proc_entry);
if (myProcess32First (snapshot, &proc_entry))
do
{
uid = 0;
start_time = 0;
proc = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, proc_entry.th32ProcessID);
if (proc)
{
if (GetProcessTimes (proc, &ct, &et, &kt, &ut))
start_time = to_time_t (&ct);
get_process_owner (proc, string_sid, user_name, domain_name);
CloseHandle (proc);
}
uid = get_uid_from_string_sid (string_sid);
bless_into_proc ("pppslsss", Fields,
uid,
proc_entry.th32ProcessID,
proc_entry.th32ParentProcessID,
proc_entry.szExeFile,
start_time,
string_sid,
user_name,
domain_name
);
}
while (myProcess32Next (snapshot, &proc_entry));
CloseHandle (snapshot);
}
#endif
char*
OS_initialize()
{
init_win_result = init_win();
return NULL;
}