summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/fhandler.h5
-rw-r--r--winsup/cygwin/fhandler_console.cc38
-rw-r--r--winsup/cygwin/fhandler_tty.cc118
-rw-r--r--winsup/cygwin/spawn.cc1
-rw-r--r--winsup/cygwin/tty.cc2
-rw-r--r--winsup/cygwin/tty.h2
6 files changed, 155 insertions, 11 deletions
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 2077b5245..a0c6645fb 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2127,7 +2127,7 @@ private:
int input_tcsetattr (int a, const struct termios *t);
void set_cursor_maybe ();
static bool create_invisible_console (HWINSTA);
- static bool create_invisible_console_workaround ();
+ static bool create_invisible_console_workaround (bool force);
static console_state *open_shared_console (HWND, HANDLE&, bool&);
void fix_tab_position (void);
@@ -2185,7 +2185,7 @@ private:
bool send_winch_maybe ();
void setup ();
bool set_unit ();
- static bool need_invisible ();
+ static bool need_invisible (bool force = false);
static void free_console ();
static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *);
@@ -2346,6 +2346,7 @@ class fhandler_pty_slave: public fhandler_pty_common
void mask_switch_to_pcon_in (bool mask);
void setup_locale (void);
tty *get_ttyp () { return (tty *) tc (); } /* Override as public */
+ void create_invisible_console (void);
};
#define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index a4c054e24..dd00079fa 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -53,6 +53,23 @@ fhandler_console::console_state NO_COPY *fhandler_console::shared_console_info;
bool NO_COPY fhandler_console::invisible_console;
+/* Mutex for AttachConsole()/FreeConsole() in fhandler_tty.cc */
+HANDLE NO_COPY attach_mutex;
+
+static inline void
+acquire_attach_mutex (DWORD t)
+{
+ if (attach_mutex)
+ WaitForSingleObject (attach_mutex, t);
+}
+
+static inline void
+release_attach_mutex ()
+{
+ if (attach_mutex)
+ ReleaseMutex (attach_mutex);
+}
+
/* con_ra is shared in the same process.
Only one console can exist in a process, therefore, static is suitable. */
static struct fhandler_base::rabuf_t con_ra;
@@ -599,6 +616,8 @@ fhandler_console::process_input_message (void)
if (!shared_console_info)
return input_error;
+ acquire_attach_mutex (INFINITE);
+
termios *ti = &(get_ttyp ()->ti);
fhandler_console::input_states stat = input_processing;
@@ -608,6 +627,7 @@ fhandler_console::process_input_message (void)
if (!PeekConsoleInputW (get_handle (), input_rec, INREC_SIZE, &total_read))
{
termios_printf ("PeekConsoleInput failed, %E");
+ release_attach_mutex ();
return input_error;
}
@@ -972,6 +992,7 @@ out:
/* Discard processed recored. */
DWORD dummy;
ReadConsoleInputW (get_handle (), input_rec, min (total_read, i+1), &dummy);
+ release_attach_mutex ();
return stat;
}
@@ -2973,6 +2994,7 @@ fhandler_console::write (const void *vsrc, size_t len)
if (bg <= bg_eof)
return (ssize_t) bg;
+ acquire_attach_mutex (INFINITE);
push_process_state process_state (PID_TTYOU);
acquire_output_mutex (INFINITE);
@@ -3298,6 +3320,7 @@ fhandler_console::write (const void *vsrc, size_t len)
syscall_printf ("%ld = fhandler_console::write(...)", len);
+ release_attach_mutex ();
return len;
}
@@ -3469,12 +3492,13 @@ fhandler_console::create_invisible_console (HWINSTA horig)
function is currently only called at startup and during exec, it shouldn't
be a big deal. */
bool
-fhandler_console::create_invisible_console_workaround ()
+fhandler_console::create_invisible_console_workaround (bool force)
{
- if (!AttachConsole (-1))
+ /* If force is set, avoid to reattach to existing console. */
+ if (force || !AttachConsole (-1))
{
bool taskbar;
- DWORD err = GetLastError ();
+ DWORD err = force ? 0 : GetLastError ();
path_conv helper ("/bin/cygwin-console-helper.exe");
HANDLE hello = NULL;
HANDLE goodbye = NULL;
@@ -3559,10 +3583,12 @@ fhandler_console::free_console ()
}
bool
-fhandler_console::need_invisible ()
+fhandler_console::need_invisible (bool force)
{
BOOL b = false;
- if (exists ())
+ /* If force is set, forcibly create a new invisible console
+ even if a console device already exists. */
+ if (exists () && !force)
invisible_console = false;
else
{
@@ -3600,7 +3626,7 @@ fhandler_console::need_invisible ()
invisible_console = true;
}
else if (wincap.has_broken_alloc_console ())
- b = create_invisible_console_workaround ();
+ b = create_invisible_console_workaround (force);
else
b = create_invisible_console (h);
}
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 0c92f41d4..1ed6e2ac6 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -59,6 +59,31 @@ struct pipe_reply {
DWORD error;
};
+extern HANDLE attach_mutex; /* Defined in fhandler_console.cc */
+
+static DWORD
+get_console_process_id (DWORD pid, bool match)
+{
+ tmp_pathbuf tp;
+ DWORD *list = (DWORD *) tp.w_get ();
+ const DWORD buf_size = NT_MAX_PATH * sizeof (WCHAR) / sizeof (DWORD);
+
+ DWORD num = GetConsoleProcessList (list, buf_size);
+ if (num == 0 || num > buf_size)
+ return 0;
+
+ DWORD res = 0;
+ /* Last one is the oldest. */
+ /* https://github.com/microsoft/terminal/issues/95 */
+ for (int i = (int) num - 1; i >= 0; i--)
+ if ((match && list[i] == pid) || (!match && list[i] != pid))
+ {
+ res = list[i];
+ break;
+ }
+ return res;
+}
+
static bool isHybrid;
static void
@@ -289,7 +314,33 @@ fhandler_pty_master::accept_input ()
if (to_be_read_from_pcon ())
{
write_to = to_slave;
- UINT cp_to = GetConsoleCP ();
+
+ UINT cp_to;
+ pinfo pinfo_target = pinfo (get_ttyp ()->invisible_console_pid);
+ DWORD target_pid = 0;
+ if (pinfo_target)
+ target_pid = pinfo_target->dwProcessId;
+ pinfo pinfo_resume = pinfo (myself->ppid);
+ DWORD resume_pid;
+ if (pinfo_resume)
+ resume_pid = pinfo_resume->dwProcessId;
+ else
+ resume_pid = get_console_process_id (myself->dwProcessId, false);
+ if (target_pid && resume_pid)
+ {
+ /* Slave attaches to a different console than master.
+ Therefore reattach here. */
+ WaitForSingleObject (attach_mutex, INFINITE);
+ FreeConsole ();
+ AttachConsole (target_pid);
+ cp_to = GetConsoleCP ();
+ FreeConsole ();
+ AttachConsole (resume_pid);
+ ReleaseMutex (attach_mutex);
+ }
+ else
+ cp_to = GetConsoleCP ();
+
if (get_ttyp ()->term_code_page != cp_to)
{
static mbstate_t mbp;
@@ -659,7 +710,20 @@ 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 (_major (myself->ctty) == DEV_CONS_MAJOR
+ && !(!pinfo (myself->ppid) && getenv ("ConEmuPID")))
+ /* This process is supposed to be a master process which is
+ running on console. Invisible console will be created in
+ primary slave process to prevent overriding code page
+ of root console by setup_locale(). */
+ /* ... except for ConEmu cygwin-connector in which this
+ code does not work as expected because it calls Win32
+ API directly rather than cygwin read()/write(). Due to
+ this behaviour, protection based on attach_mutex does
+ not take effect. */
+ get_ttyp ()->need_invisible_console = true;
+ else
+ fhandler_console::need_invisible ();
set_open_status ();
return 1;
@@ -1572,6 +1636,7 @@ fhandler_pty_master::close ()
}
release_output_mutex ();
master_fwd_thread->terminate_thread ();
+ CloseHandle (attach_mutex);
}
}
@@ -1847,6 +1912,7 @@ void
fhandler_pty_slave::fixup_after_exec ()
{
reset_switch_to_pcon ();
+ create_invisible_console ();
if (!close_on_exec ())
fixup_after_fork (NULL); /* No parent handle required. */
@@ -2135,7 +2201,32 @@ fhandler_pty_master::pty_master_fwd_thread ()
continue;
}
- UINT cp_from = GetConsoleOutputCP ();
+ UINT cp_from;
+ pinfo pinfo_target = pinfo (get_ttyp ()->invisible_console_pid);
+ DWORD target_pid = 0;
+ if (pinfo_target)
+ target_pid = pinfo_target->dwProcessId;
+ pinfo pinfo_resume = pinfo (myself->ppid);
+ DWORD resume_pid;
+ if (pinfo_resume)
+ resume_pid = pinfo_resume->dwProcessId;
+ else
+ resume_pid = get_console_process_id (myself->dwProcessId, false);
+ if (target_pid && resume_pid)
+ {
+ /* Slave attaches to a different console than master.
+ Therefore reattach here. */
+ WaitForSingleObject (attach_mutex, INFINITE);
+ FreeConsole ();
+ AttachConsole (target_pid);
+ cp_from = GetConsoleOutputCP ();
+ FreeConsole ();
+ AttachConsole (resume_pid);
+ ReleaseMutex (attach_mutex);
+ }
+ else
+ cp_from = GetConsoleOutputCP ();
+
if (get_ttyp ()->term_code_page != cp_from)
{
size_t nlen = NT_MAX_PATH;
@@ -2250,6 +2341,8 @@ fhandler_pty_master::setup ()
if (!(input_mutex = CreateMutex (&sa, FALSE, buf)))
goto err;
+ attach_mutex = CreateMutex (&sa, FALSE, NULL);
+
/* Create master control pipe which allows the master to duplicate
the pty pipe handles to processes which deserve it. */
__small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
@@ -2311,6 +2404,7 @@ err:
close_maybe (input_available_event);
close_maybe (output_mutex);
close_maybe (input_mutex);
+ close_maybe (attach_mutex);
close_maybe (from_master);
close_maybe (from_master_cyg);
close_maybe (to_master);
@@ -2757,3 +2851,21 @@ maybe_dumb:
get_ttyp ()->pcon_cap_checked = true;
return false;
}
+
+void
+fhandler_pty_slave::create_invisible_console ()
+{
+ if (get_ttyp ()->need_invisible_console)
+ {
+ /* Detach from console device and create new invisible console. */
+ FreeConsole();
+ fhandler_console::need_invisible (true);
+ get_ttyp ()->need_invisible_console = false;
+ get_ttyp ()->invisible_console_pid = myself->pid;
+ }
+ if (get_ttyp ()->invisible_console_pid
+ && !pinfo (get_ttyp ()->invisible_console_pid))
+ /* If primary slave process does not exist anymore,
+ this process becomes the primary. */
+ get_ttyp ()->invisible_console_pid = myself->pid;
+}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index bf1b08057..42044ab53 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -648,6 +648,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
{
fhandler_pty_slave *ptys =
(fhandler_pty_slave *)(fhandler_base *) cfd;
+ ptys->create_invisible_console ();
ptys->setup_locale ();
}
}
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index d4b8d7651..c6e13f111 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -246,6 +246,8 @@ tty::init ()
has_csi6n = false;
has_set_title = false;
do_not_resize_pcon = false;
+ need_invisible_console = false;
+ invisible_console_pid = 0;
}
HANDLE
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 2c1ac7f5d..a975aba45 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -105,6 +105,8 @@ private:
bool has_csi6n;
bool has_set_title;
bool do_not_resize_pcon;
+ bool need_invisible_console;
+ pid_t invisible_console_pid;
public:
HANDLE from_master () const { return _from_master; }