[PATCH v2 1/1] Cygwin: pty: Fix state management for pseudo console support.
Takashi Yano
takashi.yano@nifty.ne.jp
Sat Aug 31 22:55:00 GMT 2019
- Pseudo console support introduced by commit
169d65a5774acc76ce3f3feeedcbae7405aa9b57 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.
---
winsup/cygwin/dtable.cc | 15 +-
winsup/cygwin/fhandler.h | 6 +-
winsup/cygwin/fhandler_console.cc | 6 +-
winsup/cygwin/fhandler_tty.cc | 404 ++++++++++++++++--------------
winsup/cygwin/fork.cc | 24 +-
winsup/cygwin/spawn.cc | 65 ++---
6 files changed, 283 insertions(+), 237 deletions(-)
diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index ba5d16206..6266f1bc2 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -150,8 +150,11 @@ dtable::stdio_init ()
bool need_fixup_handle = false;
fhandler_pty_slave *ptys = NULL;
bool is_pty[3] = {false, false, false};
- for (int fd = 0; fd < 3; fd ++)
+ bool already_attached = false;
+ int chk_order[] = {1, 0, 2};
+ for (int i = 0; i < 3; i ++)
{
+ int fd = chk_order[i];
fhandler_base *fh = cygheap->fdtab[fd];
if (fh && fh->get_major () == DEV_PTYS_MAJOR)
{
@@ -161,14 +164,18 @@ dtable::stdio_init ()
is_pty[fd] = true;
bool attached = !!fhandler_console::get_console_process_id
(ptys->getHelperProcessId (), true);
- if (!attached)
+ already_attached = already_attached || attached;
+ if (!already_attached)
{
/* Not attached to pseudo console in fork() or spawn()
by some reason. This happens if the executable is
a windows GUI binary, such as mintty. */
FreeConsole ();
- AttachConsole (ptys->getHelperProcessId ());
- need_fixup_handle = true;
+ if (AttachConsole (ptys->getHelperProcessId ()))
+ {
+ need_fixup_handle = true;
+ already_attached = true;
+ }
}
ptys->reset_switch_to_pcon ();
}
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index c75e40c0a..af2b948cb 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2106,19 +2106,22 @@ class fhandler_pty_common: public fhandler_termios
protected:
BOOL process_opost_output (HANDLE h,
const void *ptr, ssize_t& len, bool is_echo);
- bool check_switch_to_pcon (void);
};
class fhandler_pty_slave: public fhandler_pty_common
{
HANDLE inuse; // used to indicate that a tty is in use
HANDLE output_handle_cyg, io_handle_cyg;
+ DWORD pidRestore;
/* Helper functions for fchmod and fchown. */
bool fch_open_handles (bool chown);
int fch_set_sd (security_descriptor &sd, bool chown);
void fch_close_handles ();
+ bool try_reattach_pcon ();
+ void restore_reattach_pcon ();
+
public:
/* Constructor */
fhandler_pty_slave (int);
@@ -2172,7 +2175,6 @@ class fhandler_pty_slave: public fhandler_pty_common
void set_switch_to_pcon (void);
void reset_switch_to_pcon (void);
void push_to_pcon_screenbuffer (const char *ptr, size_t len);
- bool has_master_opened (void);
void mask_switch_to_pcon (bool mask)
{
get_ttyp ()->mask_switch_to_pcon = mask;
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 997c50d23..ae7f66b80 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -3138,14 +3138,14 @@ fhandler_console::get_console_process_id (DWORD pid, bool match)
DWORD tmp;
int num = GetConsoleProcessList (&tmp, 1);
DWORD *list = (DWORD *)
- HeapAlloc (GetProcessHeap (), 0, num * sizeof (DWORD));
- num = GetConsoleProcessList (list, num);
+ HeapAlloc (GetProcessHeap (), 0, (num + 16) * sizeof (DWORD));
+ num = GetConsoleProcessList (list, num + 16);
tmp = 0;
for (int i=0; i<num; i++)
if ((match && list[i] == pid) || (!match && list[i] != pid))
{
tmp = list[i];
- //break;
+ break;
}
HeapFree (GetProcessHeap (), 0, list);
return tmp;
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index dd5ab528a..f0f36b0b0 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -71,7 +71,7 @@ struct pipe_reply {
DWORD error;
};
-static bool pcon_attached[NTTYS];
+static int pcon_attached_to = -1;
static bool isHybrid;
#if USE_API_HOOK
@@ -129,7 +129,6 @@ set_switch_to_pcon (void)
fhandler_base *fh = cfd;
fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
ptys->set_switch_to_pcon ();
- return;
}
}
@@ -381,25 +380,6 @@ fhandler_pty_common::__release_output_mutex (const char *fn, int ln)
#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. */
void
@@ -595,7 +575,7 @@ out:
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), pidRestore (0)
{
if (unit >= 0)
dev ().parse (DEV_PTYS_MAJOR, unit);
@@ -604,32 +584,34 @@ fhandler_pty_slave::fhandler_pty_slave (int unit)
fhandler_pty_slave::~fhandler_pty_slave ()
{
if (!get_ttyp ())
- {
- /* Why it comes here? */
- init_console_handler (false);
- FreeConsole ();
- pcon_attached[get_minor ()] = false;
- }
- else if (getPseudoConsole ())
+ /* Why comes here? Who clears _tc? */
+ return;
+ mask_switch_to_pcon (false);
+ if (getPseudoConsole ())
{
int used = 0;
+ int attached = 0;
cygheap_fdenum cfd (false);
while (cfd.next () >= 0)
- if (cfd->get_major () == DEV_PTYS_MAJOR &&
- cfd->get_minor () == get_minor ())
- used ++;
-
- /* Call FreeConsole() if no pty slave on this pty is
- opened and the process is attached to the pseudo
- console corresponding to this pty. This is needed
- to make GNU screen and tmux work in Windows 10 1903. */
- if (used == 0 &&
- fhandler_console::get_console_process_id (getHelperProcessId (),
- true))
+ {
+ if (cfd->get_major () == DEV_PTYS_MAJOR ||
+ 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 tty is opened and the process
+ is attached to console corresponding to tty. This is
+ needed to make GNU screen and tmux work in Windows 10
+ 1903. */
+ if (attached == 0)
+ pcon_attached_to = -1;
+ if (used == 0)
{
init_console_handler (false);
FreeConsole ();
- pcon_attached[get_minor ()] = false;
}
}
}
@@ -813,7 +795,36 @@ fhandler_pty_slave::open (int flags, mode_t)
set_output_handle (to_master_local);
set_output_handle_cyg (to_master_cyg_local);
- fhandler_console::need_invisible ();
+ if (!getPseudoConsole () || ALWAYS_USE_PCON)
+ {
+ fhandler_console::need_invisible ();
+ pcon_attached_to = -1;
+ }
+ else if (!fhandler_console::get_console_process_id
+ (GetCurrentProcessId (), true))
+ {
+ /* Not attached to any console */
+ if (AttachConsole (getHelperProcessId ()))
+ {
+ pcon_attached_to = get_minor ();
+ init_console_handler (true);
+ }
+ else
+ {
+ 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 ();
return 1;
@@ -855,26 +866,6 @@ fhandler_pty_slave::cleanup ()
int
fhandler_pty_slave::close ()
{
-#if 0
- if (getPseudoConsole ())
- {
- INPUT_RECORD inp[128];
- DWORD n;
- PeekFunc =
- PeekConsoleInputA_Orig ? PeekConsoleInputA_Orig : PeekConsoleInput;
- PeekFunc (get_handle (), inp, 128, &n);
- bool pipe_empty = true;
- while (n-- > 0)
- if (inp[n].EventType == KEY_EVENT && inp[n].Event.KeyEvent.bKeyDown)
- pipe_empty = false;
- if (pipe_empty)
- {
- /* Flush input buffer */
- size_t len = UINT_MAX;
- read (NULL, len);
- }
- }
-#endif
termios_printf ("closing last open %s handle", ttyname ());
if (inuse && !CloseHandle (inuse))
termios_printf ("CloseHandle (inuse), %E");
@@ -886,12 +877,13 @@ fhandler_pty_slave::close ()
if (!ForceCloseHandle (get_handle_cyg ()))
termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E",
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_pty_common::close ();
if (!ForceCloseHandle (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 --;
return 0;
}
@@ -936,14 +928,53 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
return ret;
}
+bool
+fhandler_pty_slave::try_reattach_pcon (void)
+{
+ pidRestore = 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;
+
+ pidRestore =
+ fhandler_console::get_console_process_id (GetCurrentProcessId (),
+ false);
+ /* If pidRestore is not set, give up. */
+ if (!pidRestore)
+ 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::set_switch_to_pcon (void)
+fhandler_pty_slave::restore_reattach_pcon (void)
{
- if (!pcon_attached[get_minor ()])
+ if (pidRestore)
{
- isHybrid = false;
- return;
+ FreeConsole ();
+ if (!AttachConsole (pidRestore))
+ {
+ system_printf ("pty%d: AttachConsole(restore=%d) failed. 0x%08lx",
+ get_minor (), pidRestore, GetLastError ());
+ pcon_attached_to = -1;
+ }
}
+ pidRestore = 0;
+}
+
+void
+fhandler_pty_slave::set_switch_to_pcon (void)
+{
if (!isHybrid)
{
reset_switch_to_pcon ();
@@ -951,6 +982,16 @@ fhandler_pty_slave::set_switch_to_pcon (void)
}
if (!get_ttyp ()->switch_to_pcon)
{
+ pidRestore = 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);
if (get_ttyp ()->pcon_pid == 0 ||
kill (get_ttyp ()->pcon_pid, 0) != 0)
@@ -980,7 +1021,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
DWORD mode;
GetConsoleMode (get_handle (), &mode);
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 ()->switch_to_pcon = false;
@@ -989,43 +1030,31 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
void
fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len)
{
- DWORD pidRestore = 0;
- if (!fhandler_console::get_console_process_id (getHelperProcessId (), true))
- if (pcon_attached[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 ()])
+ bool attached =
+ !!fhandler_console::get_console_process_id (getHelperProcessId (), true);
+ if (!attached && pcon_attached_to == get_minor ())
{
- if (has_master_opened ())
- 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 ()))
+ for (DWORD t0 = GetTickCount (); GetTickCount () - t0 < 100; )
{
- system_printf ("pty%d: AttachConsole(%d) failed. (%p) %08lx",
- get_minor (), getHelperProcessId (),
- this, GetLastError ());
- goto detach;
+ Sleep (1);
+ attached = fhandler_console::get_console_process_id
+ (getHelperProcessId (), true);
+ 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. */
+ pidRestore = 0;
+ if (pcon_attached_to != get_minor ())
+ if (!try_reattach_pcon ())
+ goto detach;
+
char *buf;
size_t nlen;
DWORD origCP;
@@ -1067,7 +1096,7 @@ fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len)
}
if (!nlen) /* Nothing to be synchronized */
goto cleanup;
- if (check_switch_to_pcon ())
+ if (get_ttyp ()->switch_to_pcon)
goto cleanup;
/* Remove ESC sequence which returns results to console
input buffer. Without this, cursor position report
@@ -1122,27 +1151,7 @@ cleanup:
SetConsoleOutputCP (origCP);
HeapFree (GetProcessHeap (), 0, buf);
detach:
- if (!pcon_attached[get_minor ()])
- {
- 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;
+ restore_reattach_pcon ();
}
ssize_t __stdcall
@@ -1162,7 +1171,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
char *buf;
ssize_t nlen;
- UINT targetCodePage = (check_switch_to_pcon ()) ?
+ UINT targetCodePage = get_ttyp ()->switch_to_pcon ?
GetConsoleOutputCP () : get_ttyp ()->TermCodePage;
if (targetCodePage != get_ttyp ()->TermCodePage)
{
@@ -1189,18 +1198,25 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
nlen = len;
}
+ /* If not attached this pseudo console, try to attach temporarily. */
+ pidRestore = 0;
+ bool fallback = false;
+ if (get_ttyp ()->switch_to_pcon && pcon_attached_to != get_minor ())
+ if (!try_reattach_pcon ())
+ fallback = true;
+
DWORD dwMode, flags;
flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
!(get_ttyp ()->ti.c_oflag & ONLCR))
flags |= DISABLE_NEWLINE_AUTO_RETURN;
- if (check_switch_to_pcon ())
+ if (get_ttyp ()->switch_to_pcon && !fallback)
{
GetConsoleMode (get_output_handle (), &dwMode);
SetConsoleMode (get_output_handle (), dwMode | flags);
}
- HANDLE to =
- check_switch_to_pcon () ? get_output_handle () : get_output_handle_cyg ();
+ HANDLE to = (get_ttyp ()->switch_to_pcon && !fallback) ?
+ get_output_handle () : get_output_handle_cyg ();
acquire_output_mutex (INFINITE);
if (!process_opost_output (to, buf, nlen, false))
{
@@ -1219,9 +1235,11 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
release_output_mutex ();
HeapFree (GetProcessHeap (), 0, buf);
flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
- if (check_switch_to_pcon ())
+ if (get_ttyp ()->switch_to_pcon && !fallback)
SetConsoleMode (get_output_handle (), dwMode | flags);
+ restore_reattach_pcon ();
+
/* Push slave output to pseudo console screen buffer */
if (getPseudoConsole ())
{
@@ -1361,9 +1379,15 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
}
goto out;
}
- if (check_switch_to_pcon () &&
- !get_ttyp ()->mask_switch_to_pcon)
+ if (get_ttyp ()->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;
GetConsoleMode (get_handle (), &dwMode);
DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
@@ -1406,8 +1430,13 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
ResetEvent (input_available_event);
ReleaseMutex (input_mutex);
len = rlen;
+
+ restore_reattach_pcon ();
+ mask_switch_to_pcon (false);
return;
}
+
+do_read_cyg:
if (!bytes_available (bytes_in_pipe))
{
ReleaseMutex (input_mutex);
@@ -1675,31 +1704,12 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
case TIOCSWINSZ:
if (getPseudoConsole ())
{
- /* If not attached pseudo console yet, try to attach
- temporally. */
- DWORD pidRestore = 0;
- if (!pcon_attached[get_minor ()])
- {
- if (has_master_opened () && get_ttyp ()->attach_pcon_in_fork)
- 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;
+ /* If not attached this pseudo console, try to attach temporarily. */
+ pidRestore = 0;
+ if (pcon_attached_to != get_minor ())
+ if (!try_reattach_pcon ())
+ goto cleanup;
- FreeConsole ();
- if (!AttachConsole (getHelperProcessId ()))
- {
- system_printf ("pty%d: AttachConsole(%d) failed. (%p) %08lx",
- get_minor(), getHelperProcessId (),
- this, GetLastError ());
- goto cleanup;
- }
- }
COORD size;
size.X = ((struct winsize *) arg)->ws_col;
size.Y = ((struct winsize *) arg)->ws_row;
@@ -1717,20 +1727,9 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
rect.Bottom = size.Y-1;
SetConsoleWindowInfo (get_output_handle (), TRUE, &rect);
cleanup:
- /* Detach from pseudo console and resume. */
- 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;
- }
- }
+ restore_reattach_pcon ();
}
-resize_cyg:
+
if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
|| get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
{
@@ -2106,7 +2105,7 @@ fhandler_pty_master::close ()
ClosePseudoConsole = (VOID (WINAPI *) (HPCON)) func;
ClosePseudoConsole (getPseudoConsole ());
}
- get_ttyp ()->hPseudoConsole = NULL;
+ //get_ttyp ()->hPseudoConsole = NULL; // Do not clear for safty.
get_ttyp ()->switch_to_pcon = false;
}
if (get_ttyp ()->getsid () > 0)
@@ -2160,8 +2159,8 @@ fhandler_pty_master::write (const void *ptr, size_t len)
/* Write terminal input to to_slave pipe instead of output_handle
if current application is native console application. */
- if (check_switch_to_pcon () &&
- !get_ttyp ()->mask_switch_to_pcon)
+ if (get_ttyp ()->switch_to_pcon &&
+ (!get_ttyp ()->mask_switch_to_pcon || ALWAYS_USE_PCON))
{
char *buf;
size_t nlen;
@@ -2770,8 +2769,9 @@ fhandler_pty_slave::fixup_after_attach (bool native_maybe)
if (fhandler_console::get_console_process_id (getHelperProcessId (),
true))
{
- if (!pcon_attached[get_minor ()])
+ if (pcon_attached_to != get_minor ())
{
+ pcon_attached_to = get_minor ();
init_console_handler (true);
#if USE_OWN_NLS_FUNC
char locale[ENCODING_LEN + 1] = "C";
@@ -2856,19 +2856,20 @@ fhandler_pty_slave::fixup_after_attach (bool native_maybe)
"\033[H\033[J", 6, &n, NULL);
#endif
- pcon_attached[get_minor ()] = true;
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 ());
DWORD 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);
if (get_ttyp ()->pcon_pid == 0 ||
kill (get_ttyp ()->pcon_pid, 0) != 0)
@@ -2896,23 +2897,28 @@ fhandler_pty_slave::fixup_after_exec ()
else if (getPseudoConsole ())
{
int used = 0;
+ int attached = 0;
cygheap_fdenum cfd (false);
while (cfd.next () >= 0)
- if (cfd->get_major () == DEV_PTYS_MAJOR &&
- cfd->get_minor () == get_minor ())
- used ++;
-
- /* Call FreeConsole() if no pty slave on this pty is
- opened and the process is attached to the pseudo
- console corresponding to this pty. This is needed
- to make GNU screen and tmux work in Windows 10 1903. */
- if (used == 1 /* About to close this one */ &&
- fhandler_console::get_console_process_id (getHelperProcessId (),
- true))
+ {
+ if (cfd->get_major () == DEV_PTYS_MAJOR ||
+ 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 tty is opened and the process
+ is attached to console corresponding to tty. This is
+ needed to make GNU screen and tmux work in Windows 10
+ 1903. */
+ if (attached == 1 && get_minor () == pcon_attached_to)
+ pcon_attached_to = -1;
+ if (used == 1 /* About to close this tty */)
{
init_console_handler (false);
FreeConsole ();
- pcon_attached[get_minor ()] = false;
}
}
@@ -3119,7 +3125,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
{
/* Avoid duplicating slave output which is already sent to
to_master_cyg */
- if (!check_switch_to_pcon ())
+ if (!get_ttyp ()->switch_to_pcon)
continue;
/* Avoid setting window title to "cygwin-console-helper.exe" */
@@ -3153,6 +3159,24 @@ fhandler_pty_master::pty_master_fwd_thread ()
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;
size_t nlen;
if (get_ttyp ()->TermCodePage != CP_UTF8)
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 0c089dbe9..a3a7e7505 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -140,20 +140,24 @@ frok::child (volatile char * volatile here)
{
fhandler_base *fh = cfd;
fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
- if (ptym->getPseudoConsole () &&
- !fhandler_console::get_console_process_id (
- ptym->getHelperProcessId (), true))
-
+ if (ptym->getPseudoConsole ())
{
debug_printf ("found a PTY master %d: helper_PID=%d",
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 (!AttachConsole (ptym->getHelperProcessId ()))
- /* Error */;
- else
- break;
+ if (ptym->attach_pcon_in_fork ())
+ {
+ FreeConsole ();
+ if (!AttachConsole (ptym->getHelperProcessId ()))
+ /* Error */;
+ else
+ break;
+ }
}
}
}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 98612bd0f..4bb28c47b 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -578,53 +578,62 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
pidRestore = fhandler_console::get_console_process_id
(GetCurrentProcessId (), false);
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];
if (fh && fh->get_major () == DEV_PTYS_MAJOR)
{
ptys = (fhandler_pty_slave *) fh;
- if (ptys->getPseudoConsole () &&
- !fhandler_console::get_console_process_id (
- ptys->getHelperProcessId (), true))
+ if (ptys->getPseudoConsole ())
{
DWORD dwHelperProcessId = ptys->getHelperProcessId ();
debug_printf ("found a PTY slave %d: helper_PID=%d",
- fh->get_minor (), dwHelperProcessId);
- FreeConsole ();
- if (!AttachConsole (dwHelperProcessId))
+ fh->get_minor (), dwHelperProcessId);
+ if (fhandler_console::get_console_process_id
+ (dwHelperProcessId, true))
{
- /* Fallback */
- DWORD target[3] = {
- STD_INPUT_HANDLE,
- STD_OUTPUT_HANDLE,
- STD_ERROR_HANDLE
- };
- if (fd == 0)
+ /* Already attached */
+ attach_to_pcon = true;
+ break;
+ }
+ else
+ {
+ FreeConsole ();
+ if (AttachConsole (dwHelperProcessId))
{
- ptys->set_handle (ptys->get_handle_cyg ());
- SetStdHandle (target[fd],
- ptys->get_handle ());
+ attach_to_pcon = true;
+ break;
}
else
{
- ptys->set_output_handle (
- ptys->get_output_handle_cyg ());
- SetStdHandle (target[fd],
- ptys->get_output_handle ());
+ /* 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 ());
+ }
}
}
- else
- {
- init_console_handler (true);
- attach_to_pcon = true;
- break;
- }
}
}
}
if (ptys)
- ptys->fixup_after_attach (true);
+ ptys->fixup_after_attach (!iscygwin ());
loop:
/* When ruid != euid we create the new process under the current original
--
2.21.0
More information about the Cygwin-patches
mailing list