#include "cygwait.h"
#include "registry.h"
#include "tls_pbuf.h"
+#include "winf.h"
#ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
#define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016
}
static bool isHybrid;
+static HANDLE h_gdb_process;
static void
-set_switch_to_pcon (HANDLE h)
+set_switch_to_pcon (HANDLE *in, HANDLE *out, HANDLE *err, bool iscygwin)
{
cygheap_fdenum cfd (false);
int fd;
+ fhandler_base *replace_in = NULL, *replace_out = NULL, *replace_err = NULL;
+ fhandler_pty_slave *ptys_pcon = NULL;
while ((fd = cfd.next ()) >= 0)
- if (cfd->get_major () == DEV_PTYS_MAJOR)
- {
- fhandler_base *fh = cfd;
- fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
- if (h == ptys->get_handle ())
- ptys->set_switch_to_pcon ();
- return;
- }
+ {
+ if (*in == cfd->get_handle () ||
+ (fd == 0 && *in == GetStdHandle (STD_INPUT_HANDLE)))
+ replace_in = (fhandler_base *) cfd;
+ if (*out == cfd->get_output_handle () ||
+ (fd == 1 && *out == GetStdHandle (STD_OUTPUT_HANDLE)))
+ replace_out = (fhandler_base *) cfd;
+ if (*err == cfd->get_output_handle () ||
+ (fd == 2 && *err == GetStdHandle (STD_ERROR_HANDLE)))
+ replace_err = (fhandler_base *) cfd;
+ if (cfd->get_major () == DEV_PTYS_MAJOR)
+ {
+ fhandler_base *fh = cfd;
+ fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+ if (*in == ptys->get_handle ())
+ ptys_pcon = ptys;
+ }
+ }
+ if (!iscygwin && ptys_pcon)
+ ptys_pcon->set_switch_to_pcon ();
+ if (replace_in)
+ {
+ if (iscygwin && ptys_pcon->pcon_activated ())
+ *in = replace_in->get_handle_cyg ();
+ else
+ *in = replace_in->get_handle ();
+ }
+ if (replace_out)
+ *out = replace_out->get_output_handle ();
+ if (replace_err)
+ *err = replace_err->get_output_handle ();
}
#define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
BOOL inh, DWORD f, LPVOID e, LPCSTR d,
LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
{
- HANDLE h;
- if (!isHybrid)
+ STARTUPINFOEXA siex = {0, };
+ if (si->cb == sizeof (STARTUPINFOEXA))
+ siex = *(STARTUPINFOEXA *)si;
+ else
+ siex.StartupInfo = *si;
+ STARTUPINFOA *siov = &siex.StartupInfo;
+ if (!(si->dwFlags & STARTF_USESTDHANDLES))
{
- if (si->dwFlags & STARTF_USESTDHANDLES)
- h = si->hStdInput;
- else
- h = GetStdHandle (STD_INPUT_HANDLE);
- set_switch_to_pcon (h);
+ siov->dwFlags |= STARTF_USESTDHANDLES;
+ siov->hStdInput = GetStdHandle (STD_INPUT_HANDLE);
+ siov->hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
+ siov->hStdError = GetStdHandle (STD_ERROR_HANDLE);
}
- return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
+ path_conv path;
+ tmp_pathbuf tp;
+ char *prog =tp.c_get ();
+ if (n)
+ __small_sprintf (prog, "%s", n);
+ else
+ {
+ __small_sprintf (prog, "%s", c);
+ char *p = prog;
+ char *p1;
+ do
+ if ((p1 = strstr (p, ".exe")) || (p1 = strstr (p, ".com")))
+ {
+ p = p1 + 4;
+ if (*p == ' ')
+ {
+ *p = '\0';
+ path.check (prog);
+ *p = ' ';
+ }
+ else if (*p == '\0')
+ path.check (prog);
+ }
+ while (!path.exists() && p1);
+ }
+ const char *argv[] = {"", NULL}; /* Dummy */
+ av av1;
+ av1.setup ("", path, "", 1, argv, false);
+ set_switch_to_pcon (&siov->hStdInput, &siov->hStdOutput, &siov->hStdError,
+ path.iscygexec ());
+ BOOL ret = CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, siov, pi);
+ h_gdb_process = pi->hProcess;
+ DuplicateHandle (GetCurrentProcess (), h_gdb_process,
+ GetCurrentProcess (), &h_gdb_process,
+ 0, 0, DUPLICATE_SAME_ACCESS);
+ return ret;
}
static BOOL WINAPI
CreateProcessW_Hooked
BOOL inh, DWORD f, LPVOID e, LPCWSTR d,
LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
{
- HANDLE h;
- if (!isHybrid)
+ STARTUPINFOEXW siex = {0, };
+ if (si->cb == sizeof (STARTUPINFOEXW))
+ siex = *(STARTUPINFOEXW *)si;
+ else
+ siex.StartupInfo = *si;
+ STARTUPINFOW *siov = &siex.StartupInfo;
+ if (!(si->dwFlags & STARTF_USESTDHANDLES))
{
- if (si->dwFlags & STARTF_USESTDHANDLES)
- h = si->hStdInput;
- else
- h = GetStdHandle (STD_INPUT_HANDLE);
- set_switch_to_pcon (h);
+ siov->dwFlags |= STARTF_USESTDHANDLES;
+ siov->hStdInput = GetStdHandle (STD_INPUT_HANDLE);
+ siov->hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
+ siov->hStdError = GetStdHandle (STD_ERROR_HANDLE);
}
- return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
+ path_conv path;
+ tmp_pathbuf tp;
+ char *prog =tp.c_get ();
+ if (n)
+ __small_sprintf (prog, "%W", n);
+ else
+ {
+ __small_sprintf (prog, "%W", c);
+ char *p = prog;
+ char *p1;
+ do
+ if ((p1 = strstr (p, ".exe")) || (p1 = strstr (p, ".com")))
+ {
+ p = p1 + 4;
+ if (*p == ' ')
+ {
+ *p = '\0';
+ path.check (prog);
+ *p = ' ';
+ }
+ else if (*p == '\0')
+ path.check (prog);
+ }
+ while (!path.exists() && p1);
+ }
+ const char *argv[] = {"", NULL}; /* Dummy */
+ av av1;
+ av1.setup ("", path, "", 1, argv, false);
+ set_switch_to_pcon (&siov->hStdInput, &siov->hStdOutput, &siov->hStdError,
+ path.iscygexec ());
+ BOOL ret = CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, siov, pi);
+ h_gdb_process = pi->hProcess;
+ DuplicateHandle (GetCurrentProcess (), h_gdb_process,
+ GetCurrentProcess (), &h_gdb_process,
+ 0, 0, DUPLICATE_SAME_ACCESS);
+ return ret;
}
static void
fhandler_pty_slave::fhandler_pty_slave (int unit)
: fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL),
- io_handle_cyg (NULL)
+ io_handle_cyg (NULL), slave_reading (NULL), num_reader (0)
{
if (unit >= 0)
dev ().parse (DEV_PTYS_MAJOR, unit);
if (!get_ttyp ()->switch_to_pcon_in)
{
isHybrid = true;
- if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
- get_ttyp ()->pcon_pid = myself->pid;
- get_ttyp ()->switch_to_pcon_in = true;
+ setup_locale ();
+ bool nopcon = (disable_pcon || !term_has_pcon_cap (NULL));
+ if (!setup_pseudoconsole (nopcon))
+ fhandler_pty_slave::transfer_input (fhandler_pty_slave::to_nat,
+ get_handle_cyg (),
+ get_ttyp (), get_minor (),
+ input_available_event);
}
}
void
fhandler_pty_slave::reset_switch_to_pcon (void)
{
+ if (h_gdb_process)
+ {
+ if (WaitForSingleObject (h_gdb_process, 0) == WAIT_TIMEOUT)
+ {
+ if (isHybrid)
+ get_ttyp ()->wait_pcon_fwd (false);
+ }
+ else
+ {
+ CloseHandle (h_gdb_process);
+ h_gdb_process = NULL;
+ if (isHybrid && get_ttyp ()->pcon_pid == myself->pid)
+ {
+ if (get_ttyp ()->switch_to_pcon_in)
+ fhandler_pty_slave::transfer_input (fhandler_pty_slave::to_cyg,
+ get_handle (),
+ get_ttyp (), get_minor (),
+ input_available_event);
+ if (get_ttyp ()->master_is_running_as_service)
+ /* If the master is running as service, re-attaching to
+ the console of the parent process will fail.
+ Therefore, never close pseudo console here. */
+ return;
+ bool need_restore_handles = !!get_ttyp ()->h_pseudo_console;
+ close_pseudoconsole (get_ttyp ());
+ if (need_restore_handles)
+ {
+ pinfo p (get_ttyp ()->master_pid);
+ HANDLE pty_owner =
+ OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId);
+ bool fix_in, fix_out, fix_err;
+ fix_in =
+ GetStdHandle (STD_INPUT_HANDLE) == get_handle ();
+ fix_out =
+ GetStdHandle (STD_OUTPUT_HANDLE) == get_output_handle ();
+ fix_err =
+ GetStdHandle (STD_ERROR_HANDLE) == get_output_handle ();
+ if (pty_owner)
+ {
+ CloseHandle (get_handle ());
+ DuplicateHandle (pty_owner, get_ttyp ()->from_master (),
+ GetCurrentProcess (), &get_handle (),
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
+ CloseHandle (get_output_handle ());
+ DuplicateHandle (pty_owner, get_ttyp ()->to_master (),
+ GetCurrentProcess (),
+ &get_output_handle (),
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
+ CloseHandle (pty_owner);
+ }
+ else
+ {
+ char pipe[MAX_PATH];
+ __small_sprintf (pipe,
+ "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
+ &cygheap->installation_key, get_minor ());
+ pipe_request req = { GetCurrentProcessId () };
+ pipe_reply repl;
+ DWORD len;
+ if (!CallNamedPipe (pipe, &req, sizeof req,
+ &repl, sizeof repl, &len, 500))
+ return; /* What can we do? */
+ CloseHandle (get_handle ());
+ set_handle (repl.from_master);
+ CloseHandle (get_output_handle ());
+ set_output_handle (repl.to_master);
+ }
+ if (fix_in)
+ SetStdHandle (STD_INPUT_HANDLE, get_handle ());
+ if (fix_out)
+ SetStdHandle (STD_OUTPUT_HANDLE, get_output_handle ());
+ if (fix_err)
+ SetStdHandle (STD_ERROR_HANDLE, get_output_handle ());
+ }
+ get_ttyp ()->pcon_pid = 0;
+ get_ttyp ()->switch_to_pcon_in = false;
+ }
+ isHybrid = false;
+ return;
+ }
+ }
if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
&& !!pinfo (get_ttyp ()->pcon_pid))
/* There is a process which is grabbing pseudo console. */
void
fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
{
+ char name[MAX_PATH];
+ shared_name (name, TTY_SLAVE_READING, get_minor ());
+ HANDLE masked = OpenEvent (READ_CONTROL, FALSE, name);
+ CloseHandle (masked);
+
+ if (mask)
+ {
+ if (InterlockedIncrement (&num_reader) == 1)
+ slave_reading = CreateEvent (&sec_none_nih, TRUE, FALSE, name);
+ }
+ else if (InterlockedDecrement (&num_reader) == 0)
+ CloseHandle (slave_reading);
+
if (get_ttyp ()->switch_to_pcon_in
&& (get_ttyp ()->pcon_pid == myself->pid
|| !get_ttyp ()->h_pseudo_console)
- && get_ttyp ()->mask_switch_to_pcon_in != mask)
+ && !!masked != mask)
{
if (mask)
fhandler_pty_slave::transfer_input (fhandler_pty_slave::to_cyg,
get_ttyp (), get_minor (),
input_available_event);
}
- get_ttyp ()->mask_switch_to_pcon_in = mask;
+ return;
}
bool
fhandler_pty_master::to_be_read_from_pcon (void)
{
+ char name[MAX_PATH];
+ shared_name (name, TTY_SLAVE_READING, get_minor ());
+ HANDLE masked = OpenEvent (READ_CONTROL, FALSE, name);
+ CloseHandle (masked);
+
return get_ttyp ()->pcon_start
- || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+ || (get_ttyp ()->switch_to_pcon_in && !masked);
}
void __reg3
return fhandler_pty_master::pty_master_fwd_thread (&p);
}
+inline static bool
+is_running_as_service (void)
+{
+ return check_token_membership (well_known_service_sid)
+ || cygheap->user.saved_sid () == well_known_system_sid;
+}
+
bool
fhandler_pty_master::setup ()
{
}
__small_sprintf (pipename, "pty%d-to-slave", unit);
+ /* FILE_FLAG_OVERLAPPED is specified here in order to prevent
+ PeekNamedPipe() from blocking in transfer_input().
+ Accordig to the official document, in order to access the handle
+ opened with FILE_FLAG_OVERLAPPED, it is mandatory to pass the
+ OVERLAPP structure, but in fact, it seems that the access will
+ fallback to the blocking access if it is not specified. */
res = fhandler_pipe::create (&sec_none, &from_master, &to_slave,
- fhandler_pty_common::pipesize, pipename, 0);
+ fhandler_pty_common::pipesize, pipename,
+ FILE_FLAG_OVERLAPPED);
if (res)
{
errstr = "input pipe";
dev ().parse (DEV_PTYM_MAJOR, unit);
+ t.master_is_running_as_service = is_running_as_service ();
+
termios_printf ("this %p, pty%d opened - from_pty <%p,%p>, to_pty %p",
this, unit, from_slave, get_handle (),
get_output_handle ());
CloseHandle (pi.hProcess);
/* Set handle */
+ if (GetStdHandle (STD_INPUT_HANDLE) == get_handle ())
+ SetStdHandle (STD_INPUT_HANDLE, hpConIn);
+ if (GetStdHandle (STD_OUTPUT_HANDLE) == get_output_handle ())
+ SetStdHandle (STD_OUTPUT_HANDLE, hpConOut);
+ if (GetStdHandle (STD_ERROR_HANDLE) == get_output_handle ())
+ SetStdHandle (STD_ERROR_HANDLE, hpConOut);
+
+ /* Fixup handles */
HANDLE orig_input_handle = get_handle ();
HANDLE orig_output_handle = get_output_handle ();
cygheap_fdenum cfd (false);
{
if (ttyp->h_pseudo_console)
{
- ttyp->wait_pcon_fwd ();
ttyp->previous_code_page = GetConsoleCP ();
ttyp->previous_output_code_page = GetConsoleOutputCP ();
FreeConsole ();