diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index 44ce75642d..3312de9373 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -327,7 +327,17 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle) dev.parse (myself->ctty); else { - dev.parse (FH_CONSOLE); + /* Check whether the inherited console is actually a pseudo + console bridging a pty. This happens when our non-Cygwin + parent was itself spawned by a Cygwin process from a pty + (e.g. bash spawning git.exe which then spawns vim). In + that case, connect to the pty slave instead of treating + the handle as a real console. */ + int pcon_minor = cygwin_shared->tty.find_pcon_pty (); + if (pcon_minor >= 0) + dev.parse (FHDEV (DEV_PTYS_MAJOR, pcon_minor)); + else + dev.parse (FH_CONSOLE); CloseHandle (handle); handle = INVALID_HANDLE_VALUE; } diff --git a/winsup/cygwin/local_includes/tty.h b/winsup/cygwin/local_includes/tty.h index 6e70a74cd7..f980599425 100644 --- a/winsup/cygwin/local_includes/tty.h +++ b/winsup/cygwin/local_includes/tty.h @@ -175,6 +175,10 @@ class tty: public tty_min void wait_fwd (); bool pty_input_state_eq (xfer_dir x) { return pty_input_state == x; } bool nat_fg (pid_t pgid); + bool has_active_pcon () const + { return pcon_activated && switch_to_nat_pipe; } + bool has_pcon_and_owner (DWORD pid) const + { return pcon_activated && switch_to_nat_pipe && nat_pipe_owner_pid == pid; } friend class fhandler_pty_common; friend class fhandler_pty_master; friend class fhandler_pty_slave; @@ -193,6 +197,7 @@ class tty_list int connect (int); void init (); tty_min *get_cttyp (); + int find_pcon_pty (); int attach (int n); static void init_session (); friend class lock_ttys; diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc index c8730e81c5..5cce05de34 100644 --- a/winsup/cygwin/tty.cc +++ b/winsup/cygwin/tty.cc @@ -123,6 +123,43 @@ tty_list::init () } } +/* Search for a pty whose pseudo console owns our console. + Return tty minor number or -1 if not found. + Called from init_std_file_from_handle() for processes started by + non-Cygwin parents to detect that inherited console handles are + from a pcon-backed pty. + + The cheap precondition (any tty with pcon active in shared memory) + short-circuits the common case where no pty has a pseudo console + active, avoiding the GetConsoleProcessList() LPC call entirely. */ +int +tty_list::find_pcon_pty () +{ + DWORD pids[128]; + DWORD count = 0; + bool got_pids = false; + + for (int i = 0; i < NTTYS; i++) + { + if (!ttys[i].has_active_pcon ()) + continue; + + /* Fetch the console process list lazily, only on first candidate. */ + if (!got_pids) + { + count = GetConsoleProcessList (pids, 128); + if (!count) + return -1; + got_pids = true; + } + + for (DWORD j = 0; j < count; j++) + if (ttys[i].has_pcon_and_owner (pids[j])) + return i; + } + return -1; +} + /* Search for a free tty and allocate it. Return tty number or -1 if error. */