Cygwin: pty: Fix state management for pseudo console support.

- Pseudo console support introduced by commit
  169d65a577 has some bugs which
  cause mismatch between state variables and real pseudo console
  state regarding console attaching and r/w pipe switching. This
  patch fixes this issue by redesigning the state management.
This commit is contained in:
Takashi Yano 2019-09-04 10:45:35 +09:00 committed by Corinna Vinschen
parent ffbb9b4971
commit 583102e7c9
6 changed files with 290 additions and 255 deletions

View File

@ -147,18 +147,16 @@ dtable::get_debugger_info ()
void void
dtable::stdio_init () dtable::stdio_init ()
{ {
bool need_fixup_handle = false; int chk_order[] = {1, 0, 2};
fhandler_pty_slave *ptys = NULL; for (int i = 0; i < 3; i ++)
bool is_pty[3] = {false, false, false};
for (int fd = 0; fd < 3; fd ++)
{ {
int fd = chk_order[i];
fhandler_base *fh = cygheap->fdtab[fd]; fhandler_base *fh = cygheap->fdtab[fd];
if (fh && fh->get_major () == DEV_PTYS_MAJOR) if (fh && fh->get_major () == DEV_PTYS_MAJOR)
{ {
ptys = (fhandler_pty_slave *) fh; fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
if (ptys->getPseudoConsole ()) if (ptys->getPseudoConsole ())
{ {
is_pty[fd] = true;
bool attached = !!fhandler_console::get_console_process_id bool attached = !!fhandler_console::get_console_process_id
(ptys->getHelperProcessId (), true); (ptys->getHelperProcessId (), true);
if (!attached) if (!attached)
@ -167,15 +165,12 @@ dtable::stdio_init ()
by some reason. This happens if the executable is by some reason. This happens if the executable is
a windows GUI binary, such as mintty. */ a windows GUI binary, such as mintty. */
FreeConsole (); FreeConsole ();
AttachConsole (ptys->getHelperProcessId ()); if (AttachConsole (ptys->getHelperProcessId ()))
need_fixup_handle = true; break;
} }
ptys->reset_switch_to_pcon ();
} }
} }
} }
if (need_fixup_handle)
goto fixup_handle;
if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT)) if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
{ {
@ -185,27 +180,6 @@ dtable::stdio_init ()
return; return;
} }
fixup_handle:
if (need_fixup_handle)
{
HANDLE h;
h = CreateFile ("CONIN$", GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, 0);
if (is_pty[0])
{
SetStdHandle (STD_INPUT_HANDLE, h);
ptys->set_handle (h);
}
h = CreateFile ("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, 0);
if (is_pty[1])
SetStdHandle (STD_OUTPUT_HANDLE, h);
if (is_pty[2])
SetStdHandle (STD_ERROR_HANDLE, h);
if (is_pty[1] || is_pty[2])
ptys->set_output_handle (h);
}
HANDLE in = GetStdHandle (STD_INPUT_HANDLE); HANDLE in = GetStdHandle (STD_INPUT_HANDLE);
HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE);
HANDLE err = GetStdHandle (STD_ERROR_HANDLE); HANDLE err = GetStdHandle (STD_ERROR_HANDLE);

View File

@ -2106,19 +2106,22 @@ class fhandler_pty_common: public fhandler_termios
protected: protected:
BOOL process_opost_output (HANDLE h, BOOL process_opost_output (HANDLE h,
const void *ptr, ssize_t& len, bool is_echo); const void *ptr, ssize_t& len, bool is_echo);
bool check_switch_to_pcon (void);
}; };
class fhandler_pty_slave: public fhandler_pty_common class fhandler_pty_slave: public fhandler_pty_common
{ {
HANDLE inuse; // used to indicate that a tty is in use HANDLE inuse; // used to indicate that a tty is in use
HANDLE output_handle_cyg, io_handle_cyg; HANDLE output_handle_cyg, io_handle_cyg;
DWORD pid_restore;
/* Helper functions for fchmod and fchown. */ /* Helper functions for fchmod and fchown. */
bool fch_open_handles (bool chown); bool fch_open_handles (bool chown);
int fch_set_sd (security_descriptor &sd, bool chown); int fch_set_sd (security_descriptor &sd, bool chown);
void fch_close_handles (); void fch_close_handles ();
bool try_reattach_pcon ();
void restore_reattach_pcon ();
public: public:
/* Constructor */ /* Constructor */
fhandler_pty_slave (int); fhandler_pty_slave (int);
@ -2172,7 +2175,6 @@ class fhandler_pty_slave: public fhandler_pty_common
void set_switch_to_pcon (void); void set_switch_to_pcon (void);
void reset_switch_to_pcon (void); void reset_switch_to_pcon (void);
void push_to_pcon_screenbuffer (const char *ptr, size_t len); void push_to_pcon_screenbuffer (const char *ptr, size_t len);
bool has_master_opened (void);
void mask_switch_to_pcon (bool mask) void mask_switch_to_pcon (bool mask)
{ {
get_ttyp ()->mask_switch_to_pcon = mask; get_ttyp ()->mask_switch_to_pcon = mask;

View File

@ -3136,16 +3136,29 @@ DWORD
fhandler_console::get_console_process_id (DWORD pid, bool match) fhandler_console::get_console_process_id (DWORD pid, bool match)
{ {
DWORD tmp; DWORD tmp;
int num = GetConsoleProcessList (&tmp, 1); DWORD num, num_req;
DWORD *list = (DWORD *) num = 1;
HeapAlloc (GetProcessHeap (), 0, num * sizeof (DWORD)); num_req = GetConsoleProcessList (&tmp, num);
num = GetConsoleProcessList (list, num); DWORD *list;
while (true)
{
list = (DWORD *)
HeapAlloc (GetProcessHeap (), 0, num_req * sizeof (DWORD));
num = num_req;
num_req = GetConsoleProcessList (list, num);
if (num_req > num)
HeapFree (GetProcessHeap (), 0, list);
else
break;
}
num = num_req;
tmp = 0; tmp = 0;
for (int i=0; i<num; i++) for (DWORD i=0; i<num; i++)
if ((match && list[i] == pid) || (!match && list[i] != pid)) if ((match && list[i] == pid) || (!match && list[i] != pid))
{ {
tmp = list[i]; tmp = list[i];
//break; break;
} }
HeapFree (GetProcessHeap (), 0, list); HeapFree (GetProcessHeap (), 0, list);
return tmp; return tmp;

View File

@ -71,7 +71,7 @@ struct pipe_reply {
DWORD error; DWORD error;
}; };
static bool pcon_attached[NTTYS]; static int pcon_attached_to = -1;
static bool isHybrid; static bool isHybrid;
#if USE_API_HOOK #if USE_API_HOOK
@ -85,7 +85,6 @@ set_switch_to_pcon (void)
fhandler_base *fh = cfd; fhandler_base *fh = cfd;
fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh; fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
ptys->set_switch_to_pcon (); ptys->set_switch_to_pcon ();
return;
} }
} }
@ -339,25 +338,6 @@ fhandler_pty_common::__release_output_mutex (const char *fn, int ln)
#endif #endif
} }
static bool switch_to_pcon_prev;
bool
fhandler_pty_common::check_switch_to_pcon (void)
{
bool switch_to_pcon_now = get_ttyp ()->switch_to_pcon;
if (!isHybrid && !switch_to_pcon_prev && switch_to_pcon_now)
{
Sleep (40);
/* Check again */
switch_to_pcon_now = get_ttyp ()->switch_to_pcon;
if (switch_to_pcon_now)
switch_to_pcon_prev = true;
}
else
switch_to_pcon_prev = switch_to_pcon_now;
return switch_to_pcon_prev;
}
/* Process pty input. */ /* Process pty input. */
void void
@ -553,7 +533,7 @@ out:
fhandler_pty_slave::fhandler_pty_slave (int unit) fhandler_pty_slave::fhandler_pty_slave (int unit)
: fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL), : fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL),
io_handle_cyg (NULL) io_handle_cyg (NULL), pid_restore (0)
{ {
if (unit >= 0) if (unit >= 0)
dev ().parse (DEV_PTYS_MAJOR, unit); dev ().parse (DEV_PTYS_MAJOR, unit);
@ -562,32 +542,33 @@ fhandler_pty_slave::fhandler_pty_slave (int unit)
fhandler_pty_slave::~fhandler_pty_slave () fhandler_pty_slave::~fhandler_pty_slave ()
{ {
if (!get_ttyp ()) if (!get_ttyp ())
{ /* Why comes here? Who clears _tc? */
/* Why it comes here? */ return;
init_console_handler (false); if (getPseudoConsole ())
FreeConsole ();
pcon_attached[get_minor ()] = false;
}
else if (getPseudoConsole ())
{ {
int used = 0; int used = 0;
int attached = 0;
cygheap_fdenum cfd (false); cygheap_fdenum cfd (false);
while (cfd.next () >= 0) while (cfd.next () >= 0)
if (cfd->get_major () == DEV_PTYS_MAJOR && {
cfd->get_minor () == get_minor ()) if (cfd->get_major () == DEV_PTYS_MAJOR ||
used ++; cfd->get_major () == DEV_CONS_MAJOR)
used ++;
if (cfd->get_major () == DEV_PTYS_MAJOR &&
cfd->get_minor () == pcon_attached_to)
attached ++;
}
/* Call FreeConsole() if no pty slave on this pty is /* Call FreeConsole() if no tty is opened and the process
opened and the process is attached to the pseudo is attached to console corresponding to tty. This is
console corresponding to this pty. This is needed needed to make GNU screen and tmux work in Windows 10
to make GNU screen and tmux work in Windows 10 1903. */ 1903. */
if (used == 0 && if (attached == 0)
fhandler_console::get_console_process_id (getHelperProcessId (), pcon_attached_to = -1;
true)) if (used == 0)
{ {
init_console_handler (false); init_console_handler (false);
FreeConsole (); FreeConsole ();
pcon_attached[get_minor ()] = false;
} }
} }
} }
@ -771,7 +752,27 @@ fhandler_pty_slave::open (int flags, mode_t)
set_output_handle (to_master_local); set_output_handle (to_master_local);
set_output_handle_cyg (to_master_cyg_local); set_output_handle_cyg (to_master_cyg_local);
fhandler_console::need_invisible (); if (!getPseudoConsole ())
{
fhandler_console::need_invisible ();
pcon_attached_to = -1;
}
else if (!fhandler_console::get_console_process_id
(GetCurrentProcessId (), true))
{
fhandler_console::need_invisible ();
pcon_attached_to = -1;
}
else if (fhandler_console::get_console_process_id
(getHelperProcessId (), true))
/* Attached to pcon of this pty */
{
pcon_attached_to = get_minor ();
init_console_handler (true);
}
else if (pcon_attached_to < 0)
fhandler_console::need_invisible ();
set_open_status (); set_open_status ();
return 1; return 1;
@ -824,12 +825,13 @@ fhandler_pty_slave::close ()
if (!ForceCloseHandle (get_handle_cyg ())) if (!ForceCloseHandle (get_handle_cyg ()))
termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E", termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E",
get_handle_cyg ()); get_handle_cyg ());
if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ())) if (!getPseudoConsole () &&
(unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
fhandler_console::free_console (); /* assumes that we are the last pty closer */ fhandler_console::free_console (); /* assumes that we are the last pty closer */
fhandler_pty_common::close (); fhandler_pty_common::close ();
if (!ForceCloseHandle (output_mutex)) if (!ForceCloseHandle (output_mutex))
termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex); termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
if (pcon_attached[get_minor ()]) if (pcon_attached_to == get_minor ())
get_ttyp ()->num_pcon_attached_slaves --; get_ttyp ()->num_pcon_attached_slaves --;
return 0; return 0;
} }
@ -874,14 +876,53 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
return ret; return ret;
} }
bool
fhandler_pty_slave::try_reattach_pcon (void)
{
pid_restore = 0;
/* Do not detach from the console because re-attaching will
fail if helper process is running as service account. */
if (pcon_attached_to >= 0 &&
cygwin_shared->tty[pcon_attached_to]->attach_pcon_in_fork)
return false;
pid_restore =
fhandler_console::get_console_process_id (GetCurrentProcessId (),
false);
/* If pid_restore is not set, give up. */
if (!pid_restore)
return false;
FreeConsole ();
if (!AttachConsole (getHelperProcessId ()))
{
system_printf ("pty%d: AttachConsole(helper=%d) failed. 0x%08lx",
get_minor (), getHelperProcessId (), GetLastError ());
return false;
}
return true;
}
void
fhandler_pty_slave::restore_reattach_pcon (void)
{
if (pid_restore)
{
FreeConsole ();
if (!AttachConsole (pid_restore))
{
system_printf ("pty%d: AttachConsole(restore=%d) failed. 0x%08lx",
get_minor (), pid_restore, GetLastError ());
pcon_attached_to = -1;
}
}
pid_restore = 0;
}
void void
fhandler_pty_slave::set_switch_to_pcon (void) fhandler_pty_slave::set_switch_to_pcon (void)
{ {
if (!pcon_attached[get_minor ()])
{
isHybrid = false;
return;
}
if (!isHybrid) if (!isHybrid)
{ {
reset_switch_to_pcon (); reset_switch_to_pcon ();
@ -889,6 +930,16 @@ fhandler_pty_slave::set_switch_to_pcon (void)
} }
if (!get_ttyp ()->switch_to_pcon) if (!get_ttyp ()->switch_to_pcon)
{ {
pid_restore = 0;
if (pcon_attached_to != get_minor ())
if (!try_reattach_pcon ())
goto skip_console_setting;
FlushConsoleInputBuffer (get_handle ());
DWORD mode;
GetConsoleMode (get_handle (), &mode);
SetConsoleMode (get_handle (), mode | ENABLE_ECHO_INPUT);
skip_console_setting:
restore_reattach_pcon ();
Sleep (20); Sleep (20);
if (get_ttyp ()->pcon_pid == 0 || if (get_ttyp ()->pcon_pid == 0 ||
kill (get_ttyp ()->pcon_pid, 0) != 0) kill (get_ttyp ()->pcon_pid, 0) != 0)
@ -904,7 +955,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
return; return;
if (isHybrid) if (isHybrid)
{ {
set_switch_to_pcon (); this->set_switch_to_pcon ();
return; return;
} }
if (get_ttyp ()->pcon_pid && if (get_ttyp ()->pcon_pid &&
@ -918,7 +969,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
DWORD mode; DWORD mode;
GetConsoleMode (get_handle (), &mode); GetConsoleMode (get_handle (), &mode);
SetConsoleMode (get_handle (), mode & ~ENABLE_ECHO_INPUT); SetConsoleMode (get_handle (), mode & ~ENABLE_ECHO_INPUT);
Sleep (60); /* Wait for pty_master_fwd_thread() */ Sleep (20); /* Wait for pty_master_fwd_thread() */
} }
get_ttyp ()->pcon_pid = 0; get_ttyp ()->pcon_pid = 0;
get_ttyp ()->switch_to_pcon = false; get_ttyp ()->switch_to_pcon = false;
@ -927,43 +978,31 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
void void
fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len) fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len)
{ {
DWORD pidRestore = 0; bool attached =
if (!fhandler_console::get_console_process_id (getHelperProcessId (), true)) !!fhandler_console::get_console_process_id (getHelperProcessId (), true);
if (pcon_attached[get_minor ()]) if (!attached && pcon_attached_to == get_minor ())
{
Sleep (20);
/* Check again */
if (!fhandler_console::get_console_process_id
(getHelperProcessId (), true))
{
system_printf ("pty%d: pcon_attach mismatch?????? (%p)",
get_minor (), this);
//pcon_attached[get_minor ()] = false;
return;
}
}
/* If not attached pseudo console yet, try to attach temporally. */
if (!pcon_attached[get_minor ()])
{ {
if (has_master_opened ()) for (DWORD t0 = GetTickCount (); GetTickCount () - t0 < 100; )
return;
pidRestore =
fhandler_console::get_console_process_id (GetCurrentProcessId (),
false);
/* If pidRestore is not set, give up to push. */
if (!pidRestore)
return;
FreeConsole ();
if (!AttachConsole (getHelperProcessId ()))
{ {
system_printf ("pty%d: AttachConsole(%d) failed. (%p) %08lx", Sleep (1);
get_minor (), getHelperProcessId (), attached = fhandler_console::get_console_process_id
this, GetLastError ()); (getHelperProcessId (), true);
goto detach; if (attached)
break;
}
if (!attached)
{
system_printf ("pty%d: pcon_attach_to mismatch??????", get_minor ());
return;
} }
} }
/* If not attached to this pseudo console, try to attach temporarily. */
pid_restore = 0;
if (pcon_attached_to != get_minor ())
if (!try_reattach_pcon ())
goto detach;
char *buf; char *buf;
size_t nlen; size_t nlen;
DWORD origCP; DWORD origCP;
@ -1005,7 +1044,7 @@ fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len)
} }
if (!nlen) /* Nothing to be synchronized */ if (!nlen) /* Nothing to be synchronized */
goto cleanup; goto cleanup;
if (check_switch_to_pcon ()) if (get_ttyp ()->switch_to_pcon)
goto cleanup; goto cleanup;
/* Remove ESC sequence which returns results to console /* Remove ESC sequence which returns results to console
input buffer. Without this, cursor position report input buffer. Without this, cursor position report
@ -1060,27 +1099,7 @@ cleanup:
SetConsoleOutputCP (origCP); SetConsoleOutputCP (origCP);
HeapFree (GetProcessHeap (), 0, buf); HeapFree (GetProcessHeap (), 0, buf);
detach: detach:
if (!pcon_attached[get_minor ()]) restore_reattach_pcon ();
{
FreeConsole ();
if (!AttachConsole (pidRestore))
{
system_printf ("pty%d: AttachConsole(%d) failed. (%p) %08lx",
get_minor (), pidRestore, this, GetLastError ());
pcon_attached[get_minor ()] = false;
}
}
}
bool
fhandler_pty_slave::has_master_opened (void)
{
cygheap_fdenum cfd (false);
while (cfd.next () >= 0)
if (cfd->get_major () == DEV_PTYM_MAJOR &&
cfd->get_minor () == get_minor ())
return true;
return false;
} }
ssize_t __stdcall ssize_t __stdcall
@ -1100,7 +1119,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
char *buf; char *buf;
ssize_t nlen; ssize_t nlen;
UINT targetCodePage = (check_switch_to_pcon ()) ? UINT targetCodePage = get_ttyp ()->switch_to_pcon ?
GetConsoleOutputCP () : get_ttyp ()->TermCodePage; GetConsoleOutputCP () : get_ttyp ()->TermCodePage;
if (targetCodePage != get_ttyp ()->TermCodePage) if (targetCodePage != get_ttyp ()->TermCodePage)
{ {
@ -1127,18 +1146,25 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
nlen = len; nlen = len;
} }
/* If not attached to this pseudo console, try to attach temporarily. */
pid_restore = 0;
bool fallback = false;
if (get_ttyp ()->switch_to_pcon && pcon_attached_to != get_minor ())
if (!try_reattach_pcon ())
fallback = true;
DWORD dwMode, flags; DWORD dwMode, flags;
flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING; flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!(get_ttyp ()->ti.c_oflag & OPOST) || if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
!(get_ttyp ()->ti.c_oflag & ONLCR)) !(get_ttyp ()->ti.c_oflag & ONLCR))
flags |= DISABLE_NEWLINE_AUTO_RETURN; flags |= DISABLE_NEWLINE_AUTO_RETURN;
if (check_switch_to_pcon ()) if (get_ttyp ()->switch_to_pcon && !fallback)
{ {
GetConsoleMode (get_output_handle (), &dwMode); GetConsoleMode (get_output_handle (), &dwMode);
SetConsoleMode (get_output_handle (), dwMode | flags); SetConsoleMode (get_output_handle (), dwMode | flags);
} }
HANDLE to = HANDLE to = (get_ttyp ()->switch_to_pcon && !fallback) ?
check_switch_to_pcon () ? get_output_handle () : get_output_handle_cyg (); get_output_handle () : get_output_handle_cyg ();
acquire_output_mutex (INFINITE); acquire_output_mutex (INFINITE);
if (!process_opost_output (to, buf, nlen, false)) if (!process_opost_output (to, buf, nlen, false))
{ {
@ -1157,8 +1183,10 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
release_output_mutex (); release_output_mutex ();
HeapFree (GetProcessHeap (), 0, buf); HeapFree (GetProcessHeap (), 0, buf);
flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING; flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (check_switch_to_pcon ()) if (get_ttyp ()->switch_to_pcon && !fallback)
SetConsoleMode (get_output_handle (), dwMode | flags); SetConsoleMode (get_output_handle (), dwMode);
restore_reattach_pcon ();
/* Push slave output to pseudo console screen buffer */ /* Push slave output to pseudo console screen buffer */
if (getPseudoConsole ()) if (getPseudoConsole ())
@ -1299,9 +1327,15 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
} }
goto out; goto out;
} }
if (check_switch_to_pcon () && if (get_ttyp ()->switch_to_pcon &&
!get_ttyp ()->mask_switch_to_pcon) (!get_ttyp ()->mask_switch_to_pcon || ALWAYS_USE_PCON))
{ {
if (!try_reattach_pcon ())
{
restore_reattach_pcon ();
goto do_read_cyg;
}
DWORD dwMode; DWORD dwMode;
GetConsoleMode (get_handle (), &dwMode); GetConsoleMode (get_handle (), &dwMode);
DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT; DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
@ -1344,8 +1378,13 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
ResetEvent (input_available_event); ResetEvent (input_available_event);
ReleaseMutex (input_mutex); ReleaseMutex (input_mutex);
len = rlen; len = rlen;
restore_reattach_pcon ();
mask_switch_to_pcon (false);
return; return;
} }
do_read_cyg:
if (!bytes_available (bytes_in_pipe)) if (!bytes_available (bytes_in_pipe))
{ {
ReleaseMutex (input_mutex); ReleaseMutex (input_mutex);
@ -1611,31 +1650,13 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
case TIOCSWINSZ: case TIOCSWINSZ:
if (getPseudoConsole ()) if (getPseudoConsole ())
{ {
/* If not attached pseudo console yet, try to attach /* If not attached to this pseudo console,
temporally. */ try to attach temporarily. */
DWORD pidRestore = 0; pid_restore = 0;
if (!pcon_attached[get_minor ()]) if (pcon_attached_to != get_minor ())
{ if (!try_reattach_pcon ())
if (has_master_opened () && get_ttyp ()->attach_pcon_in_fork) goto cleanup;
goto resize_cyg;
pidRestore = fhandler_console::get_console_process_id
(GetCurrentProcessId (), false);
/* This happens at mintty startup if fhandler_console::
need_invisible() is called in stdio_init() in dtable.cc */
if (!pidRestore) /* Give up to resize pseudo console */
goto resize_cyg;
FreeConsole ();
if (!AttachConsole (getHelperProcessId ()))
{
system_printf ("pty%d: AttachConsole(%d) failed. (%p) %08lx",
get_minor(), getHelperProcessId (),
this, GetLastError ());
goto cleanup;
}
}
COORD size; COORD size;
size.X = ((struct winsize *) arg)->ws_col; size.X = ((struct winsize *) arg)->ws_col;
size.Y = ((struct winsize *) arg)->ws_row; size.Y = ((struct winsize *) arg)->ws_row;
@ -1653,20 +1674,9 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
rect.Bottom = size.Y-1; rect.Bottom = size.Y-1;
SetConsoleWindowInfo (get_output_handle (), TRUE, &rect); SetConsoleWindowInfo (get_output_handle (), TRUE, &rect);
cleanup: cleanup:
/* Detach from pseudo console and resume. */ restore_reattach_pcon ();
if (pidRestore)
{
FreeConsole ();
if (!AttachConsole (pidRestore))
{
system_printf ("pty%d: AttachConsole(%d) failed. (%p) %08lx",
get_minor (), pidRestore,
this, GetLastError ());
pcon_attached[get_minor ()] = false;
}
}
} }
resize_cyg:
if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
|| get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col) || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
{ {
@ -2042,7 +2052,6 @@ fhandler_pty_master::close ()
ClosePseudoConsole = (VOID (WINAPI *) (HPCON)) func; ClosePseudoConsole = (VOID (WINAPI *) (HPCON)) func;
ClosePseudoConsole (getPseudoConsole ()); ClosePseudoConsole (getPseudoConsole ());
} }
get_ttyp ()->hPseudoConsole = NULL;
get_ttyp ()->switch_to_pcon = false; get_ttyp ()->switch_to_pcon = false;
} }
if (get_ttyp ()->getsid () > 0) if (get_ttyp ()->getsid () > 0)
@ -2096,8 +2105,8 @@ fhandler_pty_master::write (const void *ptr, size_t len)
/* Write terminal input to to_slave pipe instead of output_handle /* Write terminal input to to_slave pipe instead of output_handle
if current application is native console application. */ if current application is native console application. */
if (check_switch_to_pcon () && if (get_ttyp ()->switch_to_pcon &&
!get_ttyp ()->mask_switch_to_pcon) (!get_ttyp ()->mask_switch_to_pcon || ALWAYS_USE_PCON))
{ {
char *buf; char *buf;
size_t nlen; size_t nlen;
@ -2702,8 +2711,9 @@ fhandler_pty_slave::fixup_after_attach (bool native_maybe)
if (fhandler_console::get_console_process_id (getHelperProcessId (), if (fhandler_console::get_console_process_id (getHelperProcessId (),
true)) true))
{ {
if (!pcon_attached[get_minor ()]) if (pcon_attached_to != get_minor ())
{ {
pcon_attached_to = get_minor ();
init_console_handler (true); init_console_handler (true);
#if USE_OWN_NLS_FUNC #if USE_OWN_NLS_FUNC
char locale[ENCODING_LEN + 1] = "C"; char locale[ENCODING_LEN + 1] = "C";
@ -2786,19 +2796,20 @@ fhandler_pty_slave::fixup_after_attach (bool native_maybe)
WriteFile (get_output_handle_cyg (), WriteFile (get_output_handle_cyg (),
"\033[H\033[J", 6, &n, NULL); "\033[H\033[J", 6, &n, NULL);
pcon_attached[get_minor ()] = true;
get_ttyp ()->num_pcon_attached_slaves ++; get_ttyp ()->num_pcon_attached_slaves ++;
} }
} }
else
pcon_attached[get_minor ()] = false;
} }
if (pcon_attached[get_minor ()] && native_maybe) if (pcon_attached_to == get_minor () && (native_maybe || ALWAYS_USE_PCON))
{ {
FlushConsoleInputBuffer (get_handle ()); FlushConsoleInputBuffer (get_handle ());
DWORD mode; DWORD mode;
GetConsoleMode (get_handle (), &mode); GetConsoleMode (get_handle (), &mode);
SetConsoleMode (get_handle (), mode | ENABLE_ECHO_INPUT); SetConsoleMode (get_handle (),
(mode & ~ENABLE_VIRTUAL_TERMINAL_INPUT) |
ENABLE_ECHO_INPUT |
ENABLE_LINE_INPUT |
ENABLE_PROCESSED_INPUT);
Sleep (20); Sleep (20);
if (get_ttyp ()->pcon_pid == 0 || if (get_ttyp ()->pcon_pid == 0 ||
kill (get_ttyp ()->pcon_pid, 0) != 0) kill (get_ttyp ()->pcon_pid, 0) != 0)
@ -2826,23 +2837,28 @@ fhandler_pty_slave::fixup_after_exec ()
else if (getPseudoConsole ()) else if (getPseudoConsole ())
{ {
int used = 0; int used = 0;
int attached = 0;
cygheap_fdenum cfd (false); cygheap_fdenum cfd (false);
while (cfd.next () >= 0) while (cfd.next () >= 0)
if (cfd->get_major () == DEV_PTYS_MAJOR && {
cfd->get_minor () == get_minor ()) if (cfd->get_major () == DEV_PTYS_MAJOR ||
used ++; cfd->get_major () == DEV_CONS_MAJOR)
used ++;
if (cfd->get_major () == DEV_PTYS_MAJOR &&
cfd->get_minor () == pcon_attached_to)
attached ++;
}
/* Call FreeConsole() if no pty slave on this pty is /* Call FreeConsole() if no tty is opened and the process
opened and the process is attached to the pseudo is attached to console corresponding to tty. This is
console corresponding to this pty. This is needed needed to make GNU screen and tmux work in Windows 10
to make GNU screen and tmux work in Windows 10 1903. */ 1903. */
if (used == 1 /* About to close this one */ && if (attached == 1 && get_minor () == pcon_attached_to)
fhandler_console::get_console_process_id (getHelperProcessId (), pcon_attached_to = -1;
true)) if (used == 1 /* About to close this tty */)
{ {
init_console_handler (false); init_console_handler (false);
FreeConsole (); FreeConsole ();
pcon_attached[get_minor ()] = false;
} }
} }
@ -3049,7 +3065,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
{ {
/* Avoid duplicating slave output which is already sent to /* Avoid duplicating slave output which is already sent to
to_master_cyg */ to_master_cyg */
if (!check_switch_to_pcon ()) if (!get_ttyp ()->switch_to_pcon)
continue; continue;
/* Avoid setting window title to "cygwin-console-helper.exe" */ /* Avoid setting window title to "cygwin-console-helper.exe" */
@ -3064,25 +3080,42 @@ fhandler_pty_master::pty_master_fwd_thread ()
} }
else if ((state == 1 && outbuf[i] == ']') || else if ((state == 1 && outbuf[i] == ']') ||
(state == 2 && outbuf[i] == '0') || (state == 2 && outbuf[i] == '0') ||
(state == 3 && outbuf[i] == ';') || (state == 3 && outbuf[i] == ';'))
(state == 4 && outbuf[i] == '\0'))
{ {
state ++; state ++;
continue; continue;
} }
else if (state == 5 && outbuf[i] == '\a') else if (state == 4 && outbuf[i] == '\a')
{ {
memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1); memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
state = 0; state = 0;
rlen = wlen = start_at + rlen - i - 1; rlen = wlen = start_at + rlen - i - 1;
continue; continue;
} }
else if (state != 4 || outbuf[i] == '\a') else if (outbuf[i] == '\a')
{ {
state = 0; state = 0;
continue; continue;
} }
/* Remove ESC sequence which returns results to console
input buffer. Without this, cursor position report
is put into the input buffer as a garbage. */
/* Remove ESC sequence to report cursor position. */
char *p0;
while ((p0 = (char *) memmem (outbuf, rlen, "\033[6n", 4)))
{
memmove (p0, p0+4, rlen - (p0+4 - outbuf));
rlen -= 4;
}
/* Remove ESC sequence to report terminal identity. */
while ((p0 = (char *) memmem (outbuf, rlen, "\033[0c", 4)))
{
memmove (p0, p0+4, rlen - (p0+4 - outbuf));
rlen -= 4;
}
wlen = rlen;
char *buf; char *buf;
size_t nlen; size_t nlen;
if (get_ttyp ()->TermCodePage != CP_UTF8) if (get_ttyp ()->TermCodePage != CP_UTF8)

View File

@ -140,20 +140,24 @@ frok::child (volatile char * volatile here)
{ {
fhandler_base *fh = cfd; fhandler_base *fh = cfd;
fhandler_pty_master *ptym = (fhandler_pty_master *) fh; fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
if (ptym->getPseudoConsole () && if (ptym->getPseudoConsole ())
!fhandler_console::get_console_process_id (
ptym->getHelperProcessId (), true))
{ {
debug_printf ("found a PTY master %d: helper_PID=%d", debug_printf ("found a PTY master %d: helper_PID=%d",
ptym->get_minor (), ptym->getHelperProcessId ()); ptym->get_minor (), ptym->getHelperProcessId ());
if (ptym->attach_pcon_in_fork ()) if (fhandler_console::get_console_process_id (
ptym->getHelperProcessId (), true))
/* Already attached */
break;
else
{ {
FreeConsole (); if (ptym->attach_pcon_in_fork ())
if (!AttachConsole (ptym->getHelperProcessId ())) {
/* Error */; FreeConsole ();
else if (!AttachConsole (ptym->getHelperProcessId ()))
break; /* Error */;
else
break;
}
} }
} }
} }

View File

@ -578,53 +578,62 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
pidRestore = fhandler_console::get_console_process_id pidRestore = fhandler_console::get_console_process_id
(GetCurrentProcessId (), false); (GetCurrentProcessId (), false);
fhandler_pty_slave *ptys = NULL; fhandler_pty_slave *ptys = NULL;
for (int fd = 0; fd < 3; fd ++) int chk_order[] = {1, 0, 2};
for (int i = 0; i < 3; i ++)
{ {
int fd = chk_order[i];
fhandler_base *fh = ::cygheap->fdtab[fd]; fhandler_base *fh = ::cygheap->fdtab[fd];
if (fh && fh->get_major () == DEV_PTYS_MAJOR) if (fh && fh->get_major () == DEV_PTYS_MAJOR)
{ {
ptys = (fhandler_pty_slave *) fh; ptys = (fhandler_pty_slave *) fh;
if (ptys->getPseudoConsole () && if (ptys->getPseudoConsole ())
!fhandler_console::get_console_process_id (
ptys->getHelperProcessId (), true))
{ {
DWORD dwHelperProcessId = ptys->getHelperProcessId (); DWORD dwHelperProcessId = ptys->getHelperProcessId ();
debug_printf ("found a PTY slave %d: helper_PID=%d", debug_printf ("found a PTY slave %d: helper_PID=%d",
fh->get_minor (), dwHelperProcessId); fh->get_minor (), dwHelperProcessId);
FreeConsole (); if (fhandler_console::get_console_process_id
if (!AttachConsole (dwHelperProcessId)) (dwHelperProcessId, true))
{ {
/* Fallback */ /* Already attached */
DWORD target[3] = { attach_to_pcon = true;
STD_INPUT_HANDLE, break;
STD_OUTPUT_HANDLE,
STD_ERROR_HANDLE
};
if (fd == 0)
{
ptys->set_handle (ptys->get_handle_cyg ());
SetStdHandle (target[fd],
ptys->get_handle ());
}
else
{
ptys->set_output_handle (
ptys->get_output_handle_cyg ());
SetStdHandle (target[fd],
ptys->get_output_handle ());
}
} }
else else
{ {
init_console_handler (true); FreeConsole ();
attach_to_pcon = true; if (AttachConsole (dwHelperProcessId))
break; {
attach_to_pcon = true;
break;
}
else
{
/* Fallback */
DWORD target[3] = {
STD_INPUT_HANDLE,
STD_OUTPUT_HANDLE,
STD_ERROR_HANDLE
};
if (fd == 0)
{
ptys->set_handle (ptys->get_handle_cyg ());
SetStdHandle (target[fd],
ptys->get_handle ());
}
else if (fd < 3)
{
ptys->set_output_handle (
ptys->get_output_handle_cyg ());
SetStdHandle (target[fd],
ptys->get_output_handle ());
}
}
} }
} }
} }
} }
if (ptys) if (ptys)
ptys->fixup_after_attach (true); ptys->fixup_after_attach (!iscygwin ());
loop: loop:
/* When ruid != euid we create the new process under the current original /* When ruid != euid we create the new process under the current original