|
#ifndef UNICODE |
|
#define UNICODE |
|
#endif |
|
|
|
#define _WIN32_WINNT 0x0600 |
|
#include <windows.h> |
|
#include <stdio.h> |
|
#include <string.h> |
|
|
|
#define NT_SUCCESS(x) ((x) >= 0) |
|
#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 |
|
|
|
#define SystemExtendedHandleInformation 64 |
|
#define ObjectBasicInformation 0 |
|
#define ObjectNameInformation 1 |
|
#define ObjectTypeInformation 2 |
|
|
|
typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)( |
|
ULONG SystemInformationClass, |
|
PVOID SystemInformation, |
|
ULONG SystemInformationLength, |
|
PULONG ReturnLength |
|
); |
|
typedef NTSTATUS (NTAPI *_NtQueryObject)( |
|
HANDLE ObjectHandle, |
|
ULONG ObjectInformationClass, |
|
PVOID ObjectInformation, |
|
ULONG ObjectInformationLength, |
|
PULONG ReturnLength |
|
); |
|
|
|
typedef struct _UNICODE_STRING |
|
{ |
|
USHORT Length; |
|
USHORT MaximumLength; |
|
PWSTR Buffer; |
|
} UNICODE_STRING, *PUNICODE_STRING; |
|
|
|
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX |
|
{ |
|
PVOID Object; |
|
HANDLE UniqueProcessId; |
|
HANDLE HandleValue; |
|
ULONG GrantedAccess; |
|
USHORT CreatorBackTraceIndex; |
|
USHORT ObjectTypeIndex; |
|
ULONG HandleAttributes; |
|
ULONG Reserved; |
|
} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; |
|
|
|
typedef struct _SYSTEM_HANDLE_INFORMATION_EX |
|
{ |
|
ULONG_PTR NumberOfHandles; |
|
ULONG_PTR Reserved; |
|
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1]; |
|
} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; |
|
|
|
typedef enum _POOL_TYPE |
|
{ |
|
NonPagedPool, |
|
PagedPool, |
|
NonPagedPoolMustSucceed, |
|
DontUseThisType, |
|
NonPagedPoolCacheAligned, |
|
PagedPoolCacheAligned, |
|
NonPagedPoolCacheAlignedMustS |
|
} POOL_TYPE, *PPOOL_TYPE; |
|
|
|
typedef struct _OBJECT_TYPE_INFORMATION |
|
{ |
|
UNICODE_STRING Name; |
|
ULONG TotalNumberOfObjects; |
|
ULONG TotalNumberOfHandles; |
|
ULONG TotalPagedPoolUsage; |
|
ULONG TotalNonPagedPoolUsage; |
|
ULONG TotalNamePoolUsage; |
|
ULONG TotalHandleTableUsage; |
|
ULONG HighWaterNumberOfObjects; |
|
ULONG HighWaterNumberOfHandles; |
|
ULONG HighWaterPagedPoolUsage; |
|
ULONG HighWaterNonPagedPoolUsage; |
|
ULONG HighWaterNamePoolUsage; |
|
ULONG HighWaterHandleTableUsage; |
|
ULONG InvalidAttributes; |
|
GENERIC_MAPPING GenericMapping; |
|
ULONG ValidAccess; |
|
BOOLEAN SecurityRequired; |
|
BOOLEAN MaintainHandleCount; |
|
USHORT MaintainTypeList; |
|
POOL_TYPE PoolType; |
|
ULONG PagedPoolUsage; |
|
ULONG NonPagedPoolUsage; |
|
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; |
|
|
|
#define is_wprefix(s, prefix) \ |
|
(wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0) |
|
|
|
PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName) |
|
{ |
|
return GetProcAddress(GetModuleHandleA(LibraryName), ProcName); |
|
} |
|
|
|
/* return: 0: error |
|
* 1: from_master found |
|
* 2: to_master found */ |
|
int GetCygptyIoHandle(HANDLE handle, |
|
HANDLE *from_master, HANDLE *to_master, |
|
int *ptynum) |
|
{ |
|
WCHAR buf[sizeof(FILE_NAME_INFO) / sizeof(WCHAR) + MAX_PATH]; |
|
FILE_NAME_INFO *nameinfo = (FILE_NAME_INFO*) buf; |
|
WCHAR *p = nameinfo->FileName; |
|
int num, ret = 0; |
|
|
|
if (!GetFileInformationByHandleEx(handle, |
|
FileNameInfo, nameinfo, sizeof(buf))) |
|
return 0; |
|
|
|
nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0'; |
|
printf("[%p] Pipe: %S\n", handle, nameinfo->FileName); |
|
|
|
if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */ |
|
p += 8; |
|
} else if (is_wprefix(p, L"\\msys-")) { /* MSYS and MSYS2 */ |
|
p += 6; |
|
} else { |
|
return 0; |
|
} |
|
while (*p && isxdigit(*p)) /* Skip 16-digit hexadecimal. */ |
|
++p; |
|
if (is_wprefix(p, L"-pty")) { |
|
p += 4; |
|
} else { |
|
return 0; |
|
} |
|
num = (int) wcstol(p, &p, 10); /* pty number */ |
|
if (wcscmp(p, L"-from-master") == 0) { |
|
if (from_master != NULL) { |
|
*from_master = handle; |
|
} |
|
ret = 1; |
|
} else if (wcscmp(p, L"-to-master") == 0) { |
|
if (to_master != NULL) { |
|
*to_master = handle; |
|
} |
|
ret = 2; |
|
} else { |
|
return 0; |
|
} |
|
if (ptynum != NULL) { |
|
*ptynum = num; |
|
} |
|
return ret; |
|
} |
|
|
|
/* Get handle for synchronization objects. */ |
|
int GetCygptySyncHandle(HANDLE handle, |
|
HANDLE *input_mutex, HANDLE *output_mutex, |
|
HANDLE *input_avail, HANDLE *slave_alive, |
|
int *ptynum) |
|
{ |
|
_NtQueryObject NtQueryObject = |
|
GetLibraryProcAddress("ntdll.dll", "NtQueryObject"); |
|
POBJECT_TYPE_INFORMATION objectTypeInfo = NULL; |
|
PUNICODE_STRING objectNameInfo = NULL; |
|
ULONG returnLength; |
|
int num, ret = 0; |
|
int len, size; |
|
enum { Mutant, Event } handleType; |
|
|
|
/* Query the object type. */ |
|
size = 0x1000; |
|
objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(size); |
|
if (!NT_SUCCESS(NtQueryObject( |
|
handle, |
|
ObjectTypeInformation, |
|
objectTypeInfo, |
|
size, |
|
NULL))) |
|
{ |
|
printf("[%p] Error!\n", handle); |
|
goto end; |
|
} |
|
|
|
len = objectTypeInfo->Name.Length / sizeof(WCHAR); |
|
if (len == 5 |
|
&& wcsncmp(objectTypeInfo->Name.Buffer, L"Event", len) == 0) { |
|
handleType = Event; |
|
} else if (len == 6 |
|
&& wcsncmp(objectTypeInfo->Name.Buffer, L"Mutant", len) == 0) { |
|
handleType = Mutant; |
|
} else { |
|
goto end; |
|
} |
|
|
|
/* Query the object name. */ |
|
size = 0x1000; |
|
objectNameInfo = (PUNICODE_STRING)malloc(size); |
|
if (!NT_SUCCESS(NtQueryObject( |
|
handle, |
|
ObjectNameInformation, |
|
objectNameInfo, |
|
size, |
|
&returnLength))) |
|
{ |
|
/* We have the type name, so just display that. */ |
|
printf( |
|
"[%p] %.*S: (could not get name)\n", |
|
handle, |
|
objectTypeInfo->Name.Length / 2, |
|
objectTypeInfo->Name.Buffer |
|
); |
|
goto end; |
|
} |
|
|
|
/* Print the information! */ |
|
if (objectNameInfo->Length) |
|
{ |
|
WCHAR cygid[20]; |
|
WCHAR name[20]; |
|
|
|
/* The object has a name. */ |
|
printf( |
|
"[%p] %.*S: %.*S\n", |
|
handle, |
|
objectTypeInfo->Name.Length / 2, |
|
objectTypeInfo->Name.Buffer, |
|
objectNameInfo->Length / 2, |
|
objectNameInfo->Buffer |
|
); |
|
if (swscanf(objectNameInfo->Buffer, |
|
L"\\BaseNamedObjects\\cygwin%*16[^-]-%16[0-9a-f]\\cygtty.%16[a-z._]%d", |
|
cygid, name, &num) != 3 |
|
&& swscanf(objectNameInfo->Buffer, |
|
L"\\BaseNamedObjects\\msys-%*16[^-]-%16[0-9a-f]\\cygtty.%16[a-z._]%d", |
|
cygid, name, &num) != 3) { |
|
ret = 0; |
|
goto end; |
|
} |
|
printf("num=%d, %S, %S\n", num, cygid, name); |
|
if (handleType == Mutant) { |
|
if (wcscmp(name, L"input.mutex.") == 0) { |
|
if (input_mutex != NULL) { |
|
*input_mutex = handle; |
|
} |
|
ret = 1; |
|
} else if (wcscmp(name, L"output.mutex.") == 0) { |
|
if (output_mutex != NULL) { |
|
*output_mutex = handle; |
|
} |
|
ret = 2; |
|
} |
|
} else if (handleType == Event) { |
|
if (wcscmp(name, L"input.avail.") == 0) { |
|
if (input_avail != NULL) { |
|
*input_avail = handle; |
|
} |
|
ret = 3; |
|
} else if (wcscmp(name, L"slave_alive.") == 0) { |
|
if (slave_alive != NULL) { |
|
*slave_alive = handle; |
|
} |
|
ret = 4; |
|
} |
|
} |
|
if (ptynum != NULL) { |
|
*ptynum = num; |
|
} |
|
} |
|
else |
|
{ |
|
/* Print something else. */ |
|
printf( |
|
"[%p] %.*S: (unnamed)\n", |
|
handle, |
|
objectTypeInfo->Name.Length / 2, |
|
objectTypeInfo->Name.Buffer |
|
); |
|
ret = 0; |
|
} |
|
|
|
end: |
|
free(objectTypeInfo); |
|
free(objectNameInfo); |
|
|
|
return ret; |
|
} |
|
|
|
BOOL GetCygptyHandles( |
|
HANDLE *from_master, HANDLE *to_master, |
|
HANDLE *input_mutex, HANDLE *output_mutex, |
|
HANDLE *input_avail, HANDLE *slave_alive, |
|
int *ptynum) |
|
{ |
|
_NtQuerySystemInformation NtQuerySystemInformation = |
|
GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation"); |
|
NTSTATUS status; |
|
PSYSTEM_HANDLE_INFORMATION_EX handleInfo; |
|
ULONG handleInfoSize = 0x10000; |
|
ULONG pid; |
|
ULONG i; |
|
BOOL ret = TRUE; |
|
int n, r; |
|
|
|
if (from_master == NULL || to_master == NULL |
|
|| input_mutex == NULL || output_mutex == NULL |
|
|| input_avail == NULL || slave_alive == NULL |
|
|| ptynum == NULL) { |
|
return FALSE; |
|
} |
|
*from_master = INVALID_HANDLE_VALUE; |
|
*to_master = INVALID_HANDLE_VALUE; |
|
*input_mutex = INVALID_HANDLE_VALUE; |
|
*output_mutex = INVALID_HANDLE_VALUE; |
|
*input_avail = INVALID_HANDLE_VALUE; |
|
*slave_alive = INVALID_HANDLE_VALUE; |
|
*ptynum = -1; |
|
|
|
pid = GetCurrentProcessId(); |
|
|
|
handleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)malloc(handleInfoSize); |
|
if (handleInfo == NULL) { |
|
return FALSE; |
|
} |
|
|
|
/* NtQuerySystemInformation won't give us the correct buffer size, |
|
so we guess by doubling the buffer size. */ |
|
while ((status = NtQuerySystemInformation( |
|
SystemExtendedHandleInformation, |
|
handleInfo, |
|
handleInfoSize, |
|
NULL |
|
)) == STATUS_INFO_LENGTH_MISMATCH) |
|
{ |
|
PSYSTEM_HANDLE_INFORMATION_EX handleInfoTmp; |
|
|
|
handleInfoSize *= 2; |
|
handleInfoTmp = |
|
(PSYSTEM_HANDLE_INFORMATION_EX)realloc(handleInfo, handleInfoSize); |
|
if (handleInfoTmp == NULL) { |
|
ret = FALSE; |
|
goto end; |
|
} |
|
handleInfo = handleInfoTmp; |
|
} |
|
|
|
/* NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH. */ |
|
if (!NT_SUCCESS(status)) |
|
{ |
|
printf("NtQuerySystemInformation failed!\n"); |
|
ret = FALSE; |
|
goto end; |
|
} |
|
|
|
for (i = 0; i < handleInfo->NumberOfHandles; i++) |
|
{ |
|
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = handleInfo->Handles[i]; |
|
|
|
/* Check if this handle belongs to the PID the user specified. */ |
|
if (handle.UniqueProcessId != (HANDLE)pid) |
|
continue; |
|
|
|
if (GetFileType(handle.HandleValue) == FILE_TYPE_PIPE) { |
|
r = GetCygptyIoHandle(handle.HandleValue, |
|
from_master, to_master, &n); |
|
} else { |
|
r = GetCygptySyncHandle(handle.HandleValue, |
|
input_mutex, output_mutex, |
|
input_avail, slave_alive, &n); |
|
} |
|
if (r > 0) { |
|
if (*ptynum == -1) { |
|
*ptynum = n; |
|
} else if (*ptynum != n) { |
|
ret = FALSE; |
|
goto end; |
|
} |
|
} |
|
} |
|
if (*from_master == INVALID_HANDLE_VALUE |
|
|| *to_master == INVALID_HANDLE_VALUE |
|
|| *input_mutex == INVALID_HANDLE_VALUE |
|
|| *output_mutex == INVALID_HANDLE_VALUE |
|
|| *input_avail == INVALID_HANDLE_VALUE |
|
|| *slave_alive == INVALID_HANDLE_VALUE |
|
|| *ptynum == -1) { |
|
ret = FALSE; |
|
} |
|
|
|
end: |
|
free(handleInfo); |
|
|
|
return ret; |
|
} |
|
|
|
int wmain(int argc, WCHAR *argv[]) |
|
{ |
|
int ptynum; |
|
HANDLE from_master = INVALID_HANDLE_VALUE; |
|
HANDLE to_master = INVALID_HANDLE_VALUE; |
|
HANDLE input_mutex = INVALID_HANDLE_VALUE; |
|
HANDLE output_mutex = INVALID_HANDLE_VALUE; |
|
HANDLE input_avail = INVALID_HANDLE_VALUE; |
|
HANDLE slave_alive = INVALID_HANDLE_VALUE; |
|
BOOL ret; |
|
|
|
ret = GetCygptyHandles( |
|
&from_master, &to_master, |
|
&input_mutex, &output_mutex, |
|
&input_avail, &slave_alive, |
|
&ptynum); |
|
|
|
if (ret) { |
|
DWORD num; |
|
char *s = "\x1b[31mHello \x1b[32mWorld!\x1b[m\nType some key, then type Enter.\n"; |
|
int len = strlen(s); |
|
|
|
printf("pty%d, from_master: %p, to_master: %p\n", ptynum, from_master, to_master); |
|
printf("input_mutex: %p, output_mutex: %p, input_avail: %p, slave_alive: %p\n", input_mutex, output_mutex, input_avail, slave_alive); |
|
|
|
fflush(stdout); |
|
|
|
if (WaitForSingleObject(output_mutex, 500) == WAIT_OBJECT_0) { |
|
if (WriteFile(to_master, s, len, &num, NULL)) { |
|
printf("%ld bytes written.\n", num); |
|
} else { |
|
printf("WriteFile error: %ld\n", GetLastError()); |
|
} |
|
ReleaseMutex(output_mutex); |
|
} else { |
|
printf("Cannot acquire output mutex.\n"); |
|
} |
|
if (WaitForSingleObject(input_avail, 5 * 1000) == WAIT_OBJECT_0) { |
|
if (WaitForSingleObject(input_mutex, 500) == WAIT_OBJECT_0) { |
|
char buf[10]; |
|
if (ReadFile(from_master, buf, 10, &num, NULL)) { |
|
int i; |
|
for (i = 0; i < num; i++) { |
|
printf("0x%02x ", buf[i]); |
|
} |
|
printf("\n"); |
|
} else { |
|
printf("ReadFile error: %ld\n", GetLastError()); |
|
} |
|
ReleaseMutex(input_mutex); |
|
} else { |
|
printf("Cannot acquire input mutex.\n"); |
|
} |
|
} else { |
|
printf("Input timeout.\n"); |
|
} |
|
} else { |
|
printf("Cygwin pty not found\n"); |
|
} |
|
|
|
return 0; |
|
} |