Cygwin: strptime: add release note
[newlib-cygwin.git] / winsup / cygwin / fhandler / pty.cc
blob9d7ef3c9d167cd5edb161f3a857c22f18c57fc9b
1 /* fhandler_tty.cc
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 #include "winsup.h"
10 #include <stdlib.h>
11 #include <sys/param.h>
12 #include <cygwin/acl.h>
13 #include <cygwin/kd.h>
14 #include "cygerrno.h"
15 #include "security.h"
16 #include "path.h"
17 #include "fhandler.h"
18 #include "dtable.h"
19 #include "sigproc.h"
20 #include "pinfo.h"
21 #include "ntdll.h"
22 #include "cygheap.h"
23 #include "shared_info.h"
24 #include "cygthread.h"
25 #include "child_info.h"
26 #include <asm/socket.h>
27 #include "cygwait.h"
28 #include "registry.h"
29 #include "tls_pbuf.h"
30 #include "winf.h"
32 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
33 #define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016
34 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
36 extern "C" int sscanf (const char *, const char *, ...);
38 #define close_maybe(h) \
39 do { \
40 if (h && h != INVALID_HANDLE_VALUE) \
41 CloseHandle (h); \
42 } while (0)
44 /* pty master control pipe messages */
45 struct pipe_request {
46 DWORD pid;
49 /* The name *nat* comes from 'native' which means non-cygwin
50 (native windows). They are used for non-cygwin process. */
51 struct pipe_reply {
52 HANDLE from_master_nat;
53 HANDLE from_master;
54 HANDLE to_master_nat;
55 HANDLE to_master;
56 HANDLE to_slave_nat;
57 HANDLE to_slave;
58 DWORD error;
61 HANDLE NO_COPY attach_mutex;
63 DWORD acquire_attach_mutex (DWORD t)
65 if (!attach_mutex)
66 return WAIT_OBJECT_0;
67 return WaitForSingleObject (attach_mutex, t);
70 void release_attach_mutex (void)
72 if (!attach_mutex)
73 return;
74 ReleaseMutex (attach_mutex);
77 inline static bool process_alive (DWORD pid);
79 /* This functions looks for a process which attached to the same console
80 with current process and is matched to given conditions:
81 match: If true, return given pid if the process pid attaches to the
82 same console, otherwise, return 0. If false, return pid except
83 for given pid.
84 cygwin: return only process's pid which has cygwin pid.
85 stub_only: return only stub process's pid of non-cygwin process. */
86 DWORD
87 fhandler_pty_common::get_console_process_id (DWORD pid, bool match,
88 bool cygwin, bool stub_only,
89 bool nat)
91 tmp_pathbuf tp;
92 DWORD *list = (DWORD *) tp.c_get ();
93 const DWORD buf_size = NT_MAX_PATH / sizeof (DWORD);
95 DWORD num = GetConsoleProcessList (list, buf_size);
96 if (num == 0 || num > buf_size)
97 return 0;
99 DWORD res_pri = 0, res = 0;
100 /* Last one is the oldest. */
101 /* https://github.com/microsoft/terminal/issues/95 */
102 for (int i = (int) num - 1; i >= 0; i--)
103 if ((match && list[i] == pid) || (!match && list[i] != pid))
105 if (!cygwin)
107 res_pri = list[i];
108 break;
110 else
112 pinfo p (cygwin_pid (list[i]));
113 if (nat && !!p && !ISSTATE(p, PID_NOTCYGWIN))
114 continue;
115 if (!!p && p->exec_dwProcessId)
117 res_pri = stub_only ? p->exec_dwProcessId : list[i];
118 break;
120 if (!p && !res && process_alive (list[i]) && stub_only)
121 res = list[i];
122 if (!!p && !res && !stub_only)
123 res = list[i];
126 return res_pri ?: res;
129 static bool isHybrid; /* Set true if the active pipe is set to nat pipe
130 owned by myself even though the current process
131 is a cygwin process. */
132 static HANDLE h_gdb_inferior; /* Handle of GDB inferior process. */
134 static void
135 set_switch_to_nat_pipe (HANDLE *in, HANDLE *out, HANDLE *err)
137 cygheap_fdenum cfd (false);
138 int fd;
139 fhandler_base *replace_in = NULL, *replace_out = NULL, *replace_err = NULL;
140 fhandler_pty_slave *ptys = NULL;
141 while ((fd = cfd.next ()) >= 0)
143 if (*in == cfd->get_handle () ||
144 (fd == 0 && *in == GetStdHandle (STD_INPUT_HANDLE)))
145 replace_in = (fhandler_base *) cfd;
146 if (*out == cfd->get_output_handle () ||
147 (fd == 1 && *out == GetStdHandle (STD_OUTPUT_HANDLE)))
148 replace_out = (fhandler_base *) cfd;
149 if (*err == cfd->get_output_handle () ||
150 (fd == 2 && *err == GetStdHandle (STD_ERROR_HANDLE)))
151 replace_err = (fhandler_base *) cfd;
152 if (cfd->get_device () == (dev_t) myself->ctty)
154 fhandler_base *fh = cfd;
155 if (*in == fh->get_handle ()
156 || *out == fh->get_output_handle ()
157 || *err == fh->get_output_handle ())
158 ptys = (fhandler_pty_slave *) fh;
161 if (ptys)
162 ptys->set_switch_to_nat_pipe ();
163 if (replace_in)
164 *in = replace_in->get_handle_nat ();
165 if (replace_out)
166 *out = replace_out->get_output_handle_nat ();
167 if (replace_err)
168 *err = replace_err->get_output_handle_nat ();
171 /* Determine if the given path is cygwin binary. */
172 static bool
173 path_iscygexec_a_w (LPCSTR na, LPSTR ca, LPCWSTR nw, LPWSTR cw)
175 path_conv path;
176 tmp_pathbuf tp;
177 char *prog =tp.c_get ();
178 if (na)
180 __small_sprintf (prog, "%s", na);
181 find_exec (prog, path);
183 else if (nw)
185 __small_sprintf (prog, "%W", nw);
186 find_exec (prog, path);
188 else
190 if (ca)
191 __small_sprintf (prog, "%s", ca);
192 else if (cw)
193 __small_sprintf (prog, "%W", cw);
194 else
195 return true;
196 char *p = prog;
197 char *p1;
199 if ((p1 = strchr (p, ' ')) || (p1 = p + strlen (p)))
201 p = p1;
202 if (*p == ' ')
204 *p = '\0';
205 find_exec (prog, path);
206 *p = ' ';
207 p ++;
209 else if (*p == '\0')
210 find_exec (prog, path);
212 while (!path.exists() && *p);
214 const char *argv[] = {"", NULL}; /* Dummy */
215 av av1;
216 av1.setup ("", path, "", 1, argv, false);
217 return path.iscygexec ();
220 bool
221 fhandler_termios::path_iscygexec_a (LPCSTR n, LPSTR c)
223 return path_iscygexec_a_w (n, c, NULL, NULL);
226 bool
227 fhandler_termios::path_iscygexec_w (LPCWSTR n, LPWSTR c)
229 return path_iscygexec_a_w (NULL, NULL, n, c);
232 static bool atexit_func_registered = false;
233 static bool debug_process = false;
235 static void
236 atexit_func (void)
238 if (isHybrid)
240 cygheap_fdenum cfd (false);
241 while (cfd.next () >= 0)
242 if (cfd->get_device () == (dev_t) myself->ctty)
244 DWORD force_switch_to = 0;
245 if (WaitForSingleObject (h_gdb_inferior, 0) == WAIT_TIMEOUT
246 && !debug_process)
247 force_switch_to = GetProcessId (h_gdb_inferior);
248 fhandler_base *fh = cfd;
249 fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
250 tty *ttyp = (tty *) ptys->tc ();
251 bool stdin_is_ptys =
252 GetStdHandle (STD_INPUT_HANDLE) == ptys->get_handle ();
253 fhandler_pty_slave::handle_set_t handles =
255 ptys->get_handle_nat (),
256 ptys->get_input_available_event (),
257 ptys->input_mutex,
258 ptys->pipe_sw_mutex
260 fhandler_pty_slave::cleanup_for_non_cygwin_app (&handles, ttyp,
261 stdin_is_ptys,
262 force_switch_to);
263 break;
265 CloseHandle (h_gdb_inferior);
269 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
270 /* CreateProcess() is hooked for GDB etc. */
271 DEF_HOOK (CreateProcessA);
272 DEF_HOOK (CreateProcessW);
274 static BOOL
275 CreateProcessA_Hooked
276 (LPCSTR n, LPSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
277 BOOL inh, DWORD f, LPVOID e, LPCSTR d,
278 LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
280 STARTUPINFOEXA siex = {0, };
281 if (si->cb == sizeof (STARTUPINFOEXA))
282 siex = *(STARTUPINFOEXA *)si;
283 else
284 siex.StartupInfo = *si;
285 STARTUPINFOA *siov = &siex.StartupInfo;
286 if (!(si->dwFlags & STARTF_USESTDHANDLES))
288 siov->dwFlags |= STARTF_USESTDHANDLES;
289 siov->hStdInput = GetStdHandle (STD_INPUT_HANDLE);
290 siov->hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
291 siov->hStdError = GetStdHandle (STD_ERROR_HANDLE);
293 bool path_iscygexec = fhandler_termios::path_iscygexec_a (n, c);
294 if (!path_iscygexec)
295 set_switch_to_nat_pipe (&siov->hStdInput, &siov->hStdOutput,
296 &siov->hStdError);
297 BOOL ret = CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, siov, pi);
298 h_gdb_inferior = pi->hProcess;
299 DuplicateHandle (GetCurrentProcess (), h_gdb_inferior,
300 GetCurrentProcess (), &h_gdb_inferior,
301 0, 0, DUPLICATE_SAME_ACCESS);
302 debug_process = !!(f & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS));
303 if (debug_process)
304 mutex_timeout = 0; /* to avoid deadlock in GDB */
305 if (!atexit_func_registered && !path_iscygexec)
307 atexit (atexit_func);
308 atexit_func_registered = true;
310 return ret;
313 static BOOL
314 CreateProcessW_Hooked
315 (LPCWSTR n, LPWSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
316 BOOL inh, DWORD f, LPVOID e, LPCWSTR d,
317 LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
319 STARTUPINFOEXW siex = {0, };
320 if (si->cb == sizeof (STARTUPINFOEXW))
321 siex = *(STARTUPINFOEXW *)si;
322 else
323 siex.StartupInfo = *si;
324 STARTUPINFOW *siov = &siex.StartupInfo;
325 if (!(si->dwFlags & STARTF_USESTDHANDLES))
327 siov->dwFlags |= STARTF_USESTDHANDLES;
328 siov->hStdInput = GetStdHandle (STD_INPUT_HANDLE);
329 siov->hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
330 siov->hStdError = GetStdHandle (STD_ERROR_HANDLE);
332 bool path_iscygexec = fhandler_termios::path_iscygexec_w (n, c);
333 if (!path_iscygexec)
334 set_switch_to_nat_pipe (&siov->hStdInput, &siov->hStdOutput,
335 &siov->hStdError);
336 BOOL ret = CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, siov, pi);
337 h_gdb_inferior = pi->hProcess;
338 DuplicateHandle (GetCurrentProcess (), h_gdb_inferior,
339 GetCurrentProcess (), &h_gdb_inferior,
340 0, 0, DUPLICATE_SAME_ACCESS);
341 debug_process = !!(f & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS));
342 if (debug_process)
343 mutex_timeout = 0; /* to avoid deadlock in GDB */
344 if (!atexit_func_registered && !path_iscygexec)
346 atexit (atexit_func);
347 atexit_func_registered = true;
349 return ret;
352 static void
353 convert_mb_str (UINT cp_to, char *ptr_to, size_t *len_to,
354 UINT cp_from, const char *ptr_from, size_t len_from,
355 mbstate_t *mbp)
357 tmp_pathbuf tp;
358 wchar_t *wbuf = tp.w_get ();
359 int wlen = 0;
360 char *tmpbuf = tp.c_get ();
361 memcpy (tmpbuf, mbp->__value.__wchb, mbp->__count);
362 if (mbp->__count + len_from > NT_MAX_PATH)
363 len_from = NT_MAX_PATH - mbp->__count;
364 memcpy (tmpbuf + mbp->__count, ptr_from, len_from);
365 int total_len = mbp->__count + len_from;
366 mbp->__count = 0;
367 int mblen = 0;
368 for (const char *p = tmpbuf; p < tmpbuf + total_len; p += mblen)
369 /* Max bytes in multibyte char supported is 4. */
370 for (mblen = 1; mblen <= 4; mblen ++)
372 /* Try conversion */
373 int l = MultiByteToWideChar (cp_from, MB_ERR_INVALID_CHARS,
374 p, mblen,
375 wbuf + wlen, NT_MAX_PATH - wlen);
376 if (l)
377 { /* Conversion Success */
378 wlen += l;
379 break;
381 else if (mblen == 4)
382 { /* Conversion Fail */
383 l = MultiByteToWideChar (cp_from, 0, p, 1,
384 wbuf + wlen, NT_MAX_PATH - wlen);
385 wlen += l;
386 mblen = 1;
387 break;
389 else if (p + mblen == tmpbuf + total_len)
390 { /* Multibyte char incomplete */
391 memcpy (mbp->__value.__wchb, p, mblen);
392 mbp->__count = mblen;
393 break;
395 /* Retry conversion with extended length */
397 *len_to = WideCharToMultiByte (cp_to, 0, wbuf, wlen,
398 ptr_to, *len_to, NULL, NULL);
401 static bool
402 bytes_available (DWORD& n, HANDLE h)
404 DWORD navail, nleft;
405 navail = nleft = 0;
406 bool succeeded = PeekNamedPipe (h, NULL, 0, NULL, &navail, &nleft);
407 if (succeeded)
408 /* nleft should always be the right choice unless something has written 0
409 bytes to the pipe. In that pathological case we return the actual number
410 of bytes available in the pipe. See cgf-000008 for more details. */
411 n = nleft ?: navail;
412 else
414 termios_printf ("PeekNamedPipe(%p) failed, %E", h);
415 n = 0;
417 debug_only_printf ("n %u, nleft %u, navail %u", n, nleft, navail);
418 return succeeded;
421 bool
422 fhandler_pty_common::bytes_available (DWORD &n)
424 return ::bytes_available (n, get_handle ());
427 #ifdef DEBUGGING
428 static class mutex_stack
430 public:
431 const char *fn;
432 int ln;
433 const char *tname;
434 } ostack[100];
436 static int osi;
437 #endif /*DEBUGGING*/
439 void
440 fhandler_pty_master::flush_to_slave ()
442 WaitForSingleObject (input_mutex, mutex_timeout);
443 if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON))
444 accept_input ();
445 ReleaseMutex (input_mutex);
448 void
449 fhandler_pty_master::discard_input ()
451 DWORD bytes_in_pipe;
452 char buf[1024];
453 DWORD n;
455 WaitForSingleObject (input_mutex, mutex_timeout);
456 while (::bytes_available (bytes_in_pipe, from_master) && bytes_in_pipe)
457 ReadFile (from_master, buf, sizeof(buf), &n, NULL);
458 ResetEvent (input_available_event);
459 if (!get_ttyp ()->pcon_activated)
460 while (::bytes_available (bytes_in_pipe, from_master_nat) && bytes_in_pipe)
461 ReadFile (from_master_nat, buf, sizeof(buf), &n, NULL);
462 get_ttyp ()->discard_input = true;
463 ReleaseMutex (input_mutex);
466 DWORD
467 fhandler_pty_common::__acquire_output_mutex (const char *fn, int ln,
468 DWORD ms)
470 if (strace.active ())
471 strace.prntf (_STRACE_TERMIOS, fn, "(%d): pty output_mutex (%p): waiting %d ms", ln, output_mutex, ms);
472 DWORD res = WaitForSingleObject (output_mutex, ms);
473 if (res == WAIT_OBJECT_0)
475 #ifndef DEBUGGING
476 if (strace.active ())
477 strace.prntf (_STRACE_TERMIOS, fn, "(%d): pty output_mutex: acquired", ln, res);
478 #else
479 ostack[osi].fn = fn;
480 ostack[osi].ln = ln;
481 ostack[osi].tname = mythreadname ();
482 termios_printf ("acquired for %s:%d, osi %d", fn, ln, osi);
483 osi++;
484 #endif
486 return res;
489 void
490 fhandler_pty_common::__release_output_mutex (const char *fn, int ln)
492 if (ReleaseMutex (output_mutex))
494 #ifndef DEBUGGING
495 if (strace.active ())
496 strace.prntf (_STRACE_TERMIOS, fn, "(%d): pty output_mutex(%p) released", ln, output_mutex);
497 #else
498 if (osi > 0)
499 osi--;
500 termios_printf ("released(%p) at %s:%d, osi %d", output_mutex, fn, ln, osi);
501 termios_printf (" for %s:%d (%s)", ostack[osi].fn, ostack[osi].ln, ostack[osi].tname);
502 ostack[osi].ln = -ln;
503 #endif
505 #ifdef DEBUGGING
506 else if (osi > 0)
508 system_printf ("couldn't release output mutex but we seem to own it, %E");
509 try_to_debug ();
511 #endif
514 /* Process pty input. */
516 void
517 fhandler_pty_master::doecho (const void *str, DWORD len)
519 ssize_t towrite = len;
520 if (!process_opost_output (echo_w, str, towrite, true,
521 get_ttyp (), is_nonblocking ()))
522 termios_printf ("Write to echo pipe failed, %E");
526 fhandler_pty_master::accept_input ()
528 DWORD bytes_left;
529 int ret = 1;
531 char *p = rabuf () + raixget ();
532 bytes_left = eat_readahead (-1);
534 HANDLE write_to = get_output_handle ();
535 tmp_pathbuf tp;
536 if (to_be_read_from_nat_pipe ()
537 && get_ttyp ()->pty_input_state == tty::to_nat)
539 /* This code is reached if non-cygwin app is foreground and
540 pseudo console is not enabled. */
541 write_to = to_slave_nat; /* write to nat pipe rather than cyg pipe. */
543 /* Charset conversion for non-cygwin apps. */
544 UINT cp_to;
545 pinfo pinfo_target = pinfo (get_ttyp ()->invisible_console_pid);
546 DWORD target_pid = 0;
547 if (pinfo_target)
548 target_pid = pinfo_target->dwProcessId;
549 if (target_pid)
551 /* Slave attaches to a different console than master.
552 Therefore reattach here. */
553 DWORD resume_pid = attach_console_temporarily (target_pid);
554 cp_to = GetConsoleCP ();
555 resume_from_temporarily_attach (resume_pid);
557 else
558 cp_to = GetConsoleCP ();
560 if (get_ttyp ()->term_code_page != cp_to)
562 static mbstate_t mbp;
563 char *mbbuf = tp.c_get ();
564 size_t nlen = NT_MAX_PATH;
565 convert_mb_str (cp_to, mbbuf, &nlen,
566 get_ttyp ()->term_code_page, p, bytes_left, &mbp);
567 p = mbbuf;
568 bytes_left = nlen;
572 if (!bytes_left)
574 termios_printf ("sending EOF to slave");
575 get_ttyp ()->read_retval = 0;
577 else
579 BOOL rc = TRUE;
580 DWORD written = 0;
582 paranoid_printf ("about to write %u chars to slave", bytes_left);
583 /* Write line by line for transfer input. */
584 char *p0 = p;
585 char *p_cr = (char *) memchr (p0, '\r', bytes_left - (p0 - p));
586 char *p_lf = (char *) memchr (p0, '\n', bytes_left - (p0 - p));
587 DWORD n;
588 while (p_cr || p_lf)
590 char *p1 =
591 p_cr ? (p_lf ? ((p_cr + 1 == p_lf)
592 ? p_lf : min(p_cr, p_lf)) : p_cr) : p_lf;
593 n = p1 - p0 + 1;
594 rc = WriteFile (write_to, p0, n, &n, NULL);
595 if (rc)
596 written += n;
597 p0 = p1 + 1;
598 p_cr = (char *) memchr (p0, '\r', bytes_left - (p0 - p));
599 p_lf = (char *) memchr (p0, '\n', bytes_left - (p0 - p));
601 if (rc && (n = bytes_left - (p0 - p)))
603 rc = WriteFile (write_to, p0, n, &n, NULL);
604 if (rc)
605 written += n;
607 if (!rc && written == 0)
609 debug_printf ("error writing to pipe %p %E", write_to);
610 get_ttyp ()->read_retval = -1;
611 puts_readahead (p, bytes_left);
612 ret = -1;
614 else
616 get_ttyp ()->read_retval = 1;
617 p += written;
618 bytes_left -= written;
619 if (bytes_left > 0)
621 debug_printf ("to_slave pipe is full");
622 puts_readahead (p, bytes_left);
623 ret = 0;
628 if (write_to == get_output_handle ())
629 SetEvent (input_available_event); /* Set input_available_event only when
630 the data is written to cyg pipe. */
631 return ret;
634 bool
635 fhandler_pty_master::hit_eof ()
637 if (get_ttyp ()->was_opened && !get_ttyp ()->slave_alive ())
639 /* We have the only remaining open handle to this pty, and
640 the slave pty has been opened at least once. We treat
641 this as EOF. */
642 termios_printf ("all other handles closed");
643 return 1;
645 return 0;
648 /* Process pty output requests */
651 fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on)
653 size_t rlen;
654 char outbuf[OUT_BUFFER_SIZE];
655 DWORD n;
656 DWORD echo_cnt;
657 int rc = 0;
659 flush_to_slave ();
661 if (len == 0)
662 goto out;
664 for (;;)
666 n = echo_cnt = 0;
667 for (;;)
669 /* Check echo pipe first. */
670 if (::bytes_available (echo_cnt, echo_r) && echo_cnt > 0)
671 break;
672 if (!bytes_available (n))
673 goto err;
674 if (n)
675 break;
676 if (hit_eof ())
678 set_errno (EIO);
679 rc = -1;
680 goto out;
682 /* tclush can finish here. */
683 if (!buf)
684 goto out;
686 if (is_nonblocking ())
688 set_errno (EAGAIN);
689 rc = -1;
690 goto out;
692 pthread_testcancel ();
693 if (cygwait (NULL, 10, cw_sig_eintr) == WAIT_SIGNALED
694 && !_my_tls.call_signal_handler ())
696 set_errno (EINTR);
697 rc = -1;
698 goto out;
700 flush_to_slave ();
703 /* Set RLEN to the number of bytes to read from the pipe. */
704 rlen = len;
706 char *optr;
707 optr = buf;
708 if (pktmode_on && buf)
710 *optr++ = TIOCPKT_DATA;
711 rlen -= 1;
714 if (rlen == 0)
716 rc = optr - buf;
717 goto out;
720 if (rlen > sizeof outbuf)
721 rlen = sizeof outbuf;
723 /* If echo pipe has data (something has been typed or pasted), prefer
724 it over slave output. */
725 if (echo_cnt > 0)
727 if (!ReadFile (echo_r, outbuf, rlen, &n, NULL))
729 termios_printf ("ReadFile on echo pipe failed, %E");
730 goto err;
733 else if (!ReadFile (get_handle (), outbuf, rlen, &n, NULL))
735 termios_printf ("ReadFile failed, %E");
736 goto err;
739 termios_printf ("bytes read %u", n);
741 if (!buf || ((get_ttyp ()->ti.c_lflag & FLUSHO)
742 && !get_ttyp ()->mask_flusho))
743 continue; /* Discard read data */
745 memcpy (optr, outbuf, n);
746 optr += n;
747 rc = optr - buf;
748 break;
750 err:
751 if (GetLastError () == ERROR_BROKEN_PIPE)
752 rc = 0;
753 else
755 __seterrno ();
756 rc = -1;
758 break;
761 out:
762 if (buf)
763 set_mask_flusho (false);
764 termios_printf ("returning %d", rc);
765 return rc;
768 /* pty slave stuff */
770 fhandler_pty_slave::fhandler_pty_slave (int unit, dev_t via)
771 : fhandler_pty_common (), inuse (NULL), output_handle_nat (NULL),
772 io_handle_nat (NULL), slave_reading (NULL), num_reader (0)
774 dev_referred_via = via;
775 if (unit >= 0)
776 dev ().parse (DEV_PTYS_MAJOR, unit);
780 fhandler_pty_slave::open (int flags, mode_t)
782 HANDLE pty_owner;
783 HANDLE from_master_nat_local, from_master_local;
784 HANDLE to_master_nat_local, to_master_local;
785 HANDLE *handles[] =
787 &from_master_nat_local, &input_available_event, &input_mutex, &inuse,
788 &output_mutex, &to_master_nat_local, &pty_owner, &to_master_local,
789 &from_master_local, &pipe_sw_mutex,
790 NULL
793 for (HANDLE **h = handles; *h; h++)
794 **h = NULL;
796 _tc = cygwin_shared->tty[get_minor ()];
798 tcinit (false);
800 cygwin_shared->tty.attach (get_minor ());
802 /* Create synchronisation events */
803 char buf[MAX_PATH];
805 const char *errmsg = NULL;
807 if (!(output_mutex = get_ttyp ()->open_output_mutex (MAXIMUM_ALLOWED)))
809 errmsg = "open output mutex failed, %E";
810 goto err;
812 if (!(input_mutex = get_ttyp ()->open_input_mutex (MAXIMUM_ALLOWED)))
814 errmsg = "open input mutex failed, %E";
815 goto err;
817 if (!(pipe_sw_mutex
818 = get_ttyp ()->open_mutex (PIPE_SW_MUTEX, MAXIMUM_ALLOWED)))
820 errmsg = "open pipe switch mutex failed, %E";
821 goto err;
823 shared_name (buf, INPUT_AVAILABLE_EVENT, get_minor ());
824 if (!(input_available_event = OpenEvent (MAXIMUM_ALLOWED, TRUE, buf)))
826 errmsg = "open input event failed, %E";
827 goto err;
830 /* FIXME: Needs a method to eliminate tty races */
832 /* Create security attribute. Default permissions are 0620. */
833 security_descriptor sd;
834 sd.malloc (sizeof (SECURITY_DESCRIPTOR));
835 RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
836 SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE };
837 if (!create_object_sd_from_attribute (myself->uid, myself->gid,
838 S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP,
839 sd))
840 sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) sd;
841 acquire_output_mutex (mutex_timeout);
842 inuse = get_ttyp ()->create_inuse (&sa);
843 get_ttyp ()->was_opened = true;
844 release_output_mutex ();
847 if (!get_ttyp ()->from_master_nat () || !get_ttyp ()->from_master ()
848 || !get_ttyp ()->to_master_nat () || !get_ttyp ()->to_master ())
850 errmsg = "pty handles have been closed";
851 set_errno (EACCES);
852 goto err_no_errno;
855 /* Three case for duplicating the pipe handles:
856 - Either we're the master. In this case, just duplicate the handles.
857 - Or, we have the right to open the master process for handle duplication.
858 In this case, just duplicate the handles.
859 - Or, we have to ask the master process itself. In this case, send our
860 pid to the master process and check the reply. The reply contains
861 either the handles, or an error code which tells us why we didn't
862 get the handles. */
863 if (myself->pid == get_ttyp ()->master_pid)
865 /* This is the most common case, just calling openpty. */
866 termios_printf ("dup handles within myself.");
867 pty_owner = GetCurrentProcess ();
869 else
871 pinfo p (get_ttyp ()->master_pid);
872 if (!p)
873 termios_printf ("*** couldn't find pty master");
874 else
876 pty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId);
877 if (pty_owner)
878 termios_printf ("dup handles directly since I'm the owner");
881 if (pty_owner)
883 if (!DuplicateHandle (pty_owner, get_ttyp ()->from_master_nat (),
884 GetCurrentProcess (),
885 &from_master_nat_local, 0, TRUE,
886 DUPLICATE_SAME_ACCESS))
888 termios_printf ("can't duplicate input from %u/%p, %E",
889 get_ttyp ()->master_pid,
890 get_ttyp ()->from_master_nat ());
891 __seterrno ();
892 goto err_no_msg;
894 if (!DuplicateHandle (pty_owner, get_ttyp ()->from_master (),
895 GetCurrentProcess (),
896 &from_master_local, 0, TRUE,
897 DUPLICATE_SAME_ACCESS))
899 termios_printf ("can't duplicate input from %u/%p, %E",
900 get_ttyp ()->master_pid,
901 get_ttyp ()->from_master ());
902 __seterrno ();
903 goto err_no_msg;
905 if (!DuplicateHandle (pty_owner, get_ttyp ()->to_master_nat (),
906 GetCurrentProcess (),
907 &to_master_nat_local, 0, TRUE,
908 DUPLICATE_SAME_ACCESS))
910 errmsg = "can't duplicate output, %E";
911 goto err;
913 if (!DuplicateHandle (pty_owner, get_ttyp ()->to_master (),
914 GetCurrentProcess (),
915 &to_master_local, 0, TRUE,
916 DUPLICATE_SAME_ACCESS))
918 errmsg = "can't duplicate output for cygwin, %E";
919 goto err;
921 if (pty_owner != GetCurrentProcess ())
922 CloseHandle (pty_owner);
924 else
926 pipe_request req = { GetCurrentProcessId () };
927 pipe_reply repl;
928 DWORD len;
930 __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
931 &cygheap->installation_key, get_minor ());
932 termios_printf ("dup handles via master control pipe %s", buf);
933 if (!CallNamedPipe (buf, &req, sizeof req, &repl, sizeof repl,
934 &len, 500))
936 errmsg = "can't call master, %E";
937 goto err;
939 CloseHandle (repl.to_slave_nat); /* not used. */
940 CloseHandle (repl.to_slave); /* not used. */
941 from_master_nat_local = repl.from_master_nat;
942 from_master_local = repl.from_master;
943 to_master_nat_local = repl.to_master_nat;
944 to_master_local = repl.to_master;
945 if (!from_master_nat_local || !from_master_local
946 || !to_master_nat_local || !to_master_local)
948 SetLastError (repl.error);
949 errmsg = "error duplicating pipes, %E";
950 goto err;
953 VerifyHandle (from_master_nat_local);
954 VerifyHandle (from_master_local);
955 VerifyHandle (to_master_nat_local);
956 VerifyHandle (to_master_local);
958 termios_printf ("duplicated from_master_nat %p->%p from pty_owner",
959 get_ttyp ()->from_master_nat (), from_master_nat_local);
960 termios_printf ("duplicated from_master %p->%p from pty_owner",
961 get_ttyp ()->from_master (), from_master_local);
962 termios_printf ("duplicated to_master_nat %p->%p from pty_owner",
963 get_ttyp ()->to_master_nat (), to_master_nat_local);
964 termios_printf ("duplicated to_master %p->%p from pty_owner",
965 get_ttyp ()->to_master (), to_master_local);
967 set_handle_nat (from_master_nat_local);
968 set_handle (from_master_local);
969 set_output_handle_nat (to_master_nat_local);
970 set_output_handle (to_master_local);
972 if (_major (myself->ctty) == DEV_CONS_MAJOR
973 && !(!pinfo (myself->ppid) && GetModuleHandle ("ConEmuHk64.dll")))
974 /* This process is supposed to be a master process which is
975 running on console. Invisible console will be created in
976 primary slave process to prevent overriding code page
977 of root console by setup_locale(). */
978 /* ... except for ConEmu cygwin-connector in which this
979 code does not work as expected because it calls Win32
980 API directly rather than cygwin read()/write(). Due to
981 this behaviour, protection based on attach_mutex does
982 not take effect. */
983 get_ttyp ()->need_invisible_console = true;
984 else if (_major (myself->ctty) != DEV_CONS_MAJOR
985 && (!get_ttyp ()->invisible_console_pid
986 || !pinfo (get_ttyp ()->invisible_console_pid)))
987 /* Create a new invisible console for each pty to isolate
988 CTRL_C_EVENTs between ptys. */
989 get_ttyp ()->need_invisible_console = true;
990 else
992 acquire_attach_mutex (mutex_timeout);
993 fhandler_console::need_invisible ();
994 release_attach_mutex ();
997 set_open_status ();
998 return 1;
1000 err:
1001 if (GetLastError () == ERROR_FILE_NOT_FOUND)
1002 set_errno (ENXIO);
1003 else
1004 __seterrno ();
1005 err_no_errno:
1006 termios_printf (errmsg);
1007 err_no_msg:
1008 for (HANDLE **h = handles; *h; h++)
1009 if (**h && **h != INVALID_HANDLE_VALUE)
1010 CloseHandle (**h);
1011 return 0;
1014 bool
1015 fhandler_pty_slave::open_setup (int flags)
1017 set_flags ((flags & ~O_TEXT) | O_BINARY);
1018 myself->set_ctty (this, flags);
1019 report_tty_counts (this, "opened", "");
1020 return fhandler_base::open_setup (flags);
1023 void
1024 fhandler_pty_slave::cleanup ()
1026 /* This used to always call fhandler_pty_common::close when we were execing
1027 but that caused multiple closes of the handles associated with this pty.
1028 Since close_all_files is not called until after the cygwin process has
1029 synced or before a non-cygwin process has exited, it should be safe to
1030 just close this normally. cgf 2006-05-20 */
1031 report_tty_counts (this, "closed", "");
1032 fhandler_base::cleanup ();
1036 fhandler_pty_slave::close ()
1038 termios_printf ("closing last open %s handle", ttyname ());
1039 if (inuse && !CloseHandle (inuse))
1040 termios_printf ("CloseHandle (inuse), %E");
1041 if (!ForceCloseHandle (input_available_event))
1042 termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event);
1043 if (!ForceCloseHandle (get_output_handle_nat ()))
1044 termios_printf ("CloseHandle (get_output_handle_nat ()<%p>), %E",
1045 get_output_handle_nat ());
1046 if (!ForceCloseHandle (get_handle_nat ()))
1047 termios_printf ("CloseHandle (get_handle_nat ()<%p>), %E",
1048 get_handle_nat ());
1049 fhandler_pty_common::close ();
1050 if (!ForceCloseHandle (output_mutex))
1051 termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
1052 if (!get_ttyp ()->invisible_console_pid && myself->ctty == CTTY_RELEASED)
1053 FreeConsole();
1054 if (get_ttyp ()->invisible_console_pid
1055 && !pinfo (get_ttyp ()->invisible_console_pid))
1056 get_ttyp ()->invisible_console_pid = 0;
1057 return 0;
1061 fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
1063 int flags = 0;
1065 a &= GENERIC_READ | GENERIC_WRITE;
1066 if (a == GENERIC_READ)
1067 flags = O_RDONLY;
1068 if (a == GENERIC_WRITE)
1069 flags = O_WRONLY;
1070 if (a == (GENERIC_READ | GENERIC_WRITE))
1071 flags = O_RDWR;
1073 int ret = open_with_arch (flags);
1075 if (ret && !cygwin_finished_initializing && !being_debugged ())
1077 /* This only occurs when called from dtable::init_std_file_from_handle
1078 We have been started from a non-Cygwin process. So we should become
1079 pty process group leader.
1080 TODO: Investigate how SIGTTIN should be handled with pure-windows
1081 programs. */
1082 pinfo p (tc ()->getpgid ());
1083 /* We should only grab this when the process group owner for this
1084 pty is a non-cygwin process or we've been started directly
1085 from a non-Cygwin process with no Cygwin ancestry. */
1086 if (!p || ISSTATE (p, PID_NOTCYGWIN))
1088 termios_printf ("Setting process group leader to %d since %W(%d) is not a cygwin process",
1089 myself->pgid, p->progname, p->pid);
1090 tc ()->setpgid (myself->pgid);
1094 if (h != INVALID_HANDLE_VALUE)
1095 CloseHandle (h); /* Reopened by open */
1097 return ret;
1100 void
1101 fhandler_pty_slave::set_switch_to_nat_pipe (void)
1103 if (!isHybrid)
1105 isHybrid = true;
1106 setup_locale ();
1107 myself->exec_dwProcessId = myself->dwProcessId; /* Set this as a marker
1108 for tty::nat_fg()
1109 and process_sigs() */
1110 bool stdin_is_ptys = GetStdHandle (STD_INPUT_HANDLE) == get_handle ();
1111 setup_for_non_cygwin_app (false, NULL, stdin_is_ptys);
1115 inline static bool
1116 process_alive (DWORD pid)
1118 /* This function is very similar to _pinfo::alive(), however, this
1119 can be used for non-cygwin process which is started from non-cygwin
1120 shell. In addition, this checks exit code as well. */
1121 if (pid == 0)
1122 return false;
1123 HANDLE h = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
1124 if (h == NULL)
1125 return false;
1126 DWORD exit_code;
1127 BOOL r = GetExitCodeProcess (h, &exit_code);
1128 CloseHandle (h);
1129 if (r && exit_code == STILL_ACTIVE)
1130 return true;
1131 return false;
1134 inline static bool
1135 nat_pipe_owner_self (DWORD pid)
1137 return (pid == (myself->exec_dwProcessId ?: myself->dwProcessId));
1140 /* This function is called from some pty slave functions. The purpose
1141 of this function is cleaning up the nat pipe state which is marked
1142 as active but actually not used anymore. This is needed only when
1143 non-cygwin process is not terminated cleanly. */
1144 void
1145 fhandler_pty_slave::reset_switch_to_nat_pipe (void)
1147 if (h_gdb_inferior)
1149 if (WaitForSingleObject (h_gdb_inferior, 0) == WAIT_TIMEOUT)
1151 if (isHybrid)
1152 get_ttyp ()->wait_fwd ();
1154 else
1156 CloseHandle (h_gdb_inferior);
1157 h_gdb_inferior = NULL;
1158 mutex_timeout = INFINITE;
1159 if (isHybrid)
1161 if (get_ttyp ()->getpgid () == myself->pgid
1162 && GetStdHandle (STD_INPUT_HANDLE) == get_handle ()
1163 && get_ttyp ()->pty_input_state_eq (tty::to_nat))
1165 WaitForSingleObject (input_mutex, mutex_timeout);
1166 acquire_attach_mutex (mutex_timeout);
1167 transfer_input (tty::to_cyg, get_handle_nat (), get_ttyp (),
1168 input_available_event);
1169 release_attach_mutex ();
1170 ReleaseMutex (input_mutex);
1172 if (get_ttyp ()->master_is_running_as_service
1173 && get_ttyp ()->pcon_activated)
1174 /* If the master is running as service, re-attaching to
1175 the console of the parent process will fail.
1176 Therefore, never close pseudo console here. */
1177 return;
1178 bool need_restore_handles = get_ttyp ()->pcon_activated;
1179 WaitForSingleObject (pipe_sw_mutex, INFINITE);
1180 if (get_ttyp ()->pcon_activated)
1181 close_pseudoconsole (get_ttyp ());
1182 else
1183 hand_over_only (get_ttyp ());
1184 ReleaseMutex (pipe_sw_mutex);
1185 if (need_restore_handles)
1187 pinfo p (get_ttyp ()->master_pid);
1188 HANDLE pty_owner =
1189 OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId);
1190 if (pty_owner)
1192 CloseHandle (get_handle_nat ());
1193 DuplicateHandle (pty_owner,
1194 get_ttyp ()->from_master_nat (),
1195 GetCurrentProcess (), &get_handle_nat (),
1196 0, TRUE, DUPLICATE_SAME_ACCESS);
1197 CloseHandle (get_output_handle_nat ());
1198 DuplicateHandle (pty_owner,
1199 get_ttyp ()->to_master_nat (),
1200 GetCurrentProcess (),
1201 &get_output_handle_nat (),
1202 0, TRUE, DUPLICATE_SAME_ACCESS);
1203 CloseHandle (pty_owner);
1205 else
1207 char pipe[MAX_PATH];
1208 __small_sprintf (pipe,
1209 "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
1210 &cygheap->installation_key, get_minor ());
1211 pipe_request req = { GetCurrentProcessId () };
1212 pipe_reply repl;
1213 DWORD len;
1214 if (!CallNamedPipe (pipe, &req, sizeof req,
1215 &repl, sizeof repl, &len, 500))
1216 return; /* What can we do? */
1217 CloseHandle (repl.from_master); /* not used. */
1218 CloseHandle (repl.to_master); /* not used. */
1219 CloseHandle (repl.to_slave_nat); /* not used. */
1220 CloseHandle (repl.to_slave); /* not used. */
1221 CloseHandle (get_handle_nat ());
1222 set_handle_nat (repl.from_master_nat);
1223 CloseHandle (get_output_handle_nat ());
1224 set_output_handle_nat (repl.to_master_nat);
1227 myself->exec_dwProcessId = 0;
1228 isHybrid = false;
1232 if (isHybrid)
1233 return;
1234 if (get_ttyp ()->pcon_start) /* Pseudo console initialization is on going */
1235 return;
1236 DWORD wait_ret = WaitForSingleObject (pipe_sw_mutex, mutex_timeout);
1237 if (wait_ret == WAIT_TIMEOUT)
1238 return;
1239 if (!nat_pipe_owner_self (get_ttyp ()->nat_pipe_owner_pid)
1240 && process_alive (get_ttyp ()->nat_pipe_owner_pid))
1242 /* There is a process which owns nat pipe. */
1243 ReleaseMutex (pipe_sw_mutex);
1244 return;
1246 /* Clean up nat pipe state */
1247 get_ttyp ()->pty_input_state = tty::to_cyg;
1248 get_ttyp ()->nat_pipe_owner_pid = 0;
1249 get_ttyp ()->switch_to_nat_pipe = false;
1250 get_ttyp ()->pcon_activated = false;
1251 ReleaseMutex (pipe_sw_mutex);
1254 ssize_t
1255 fhandler_pty_slave::write (const void *ptr, size_t len)
1257 ssize_t towrite = len;
1259 bg_check_types bg = bg_check (SIGTTOU);
1260 if (bg <= bg_eof)
1261 return (ssize_t) bg;
1263 termios_printf ("pty%d, write(%p, %lu)", get_minor (), ptr, len);
1265 push_process_state process_state (PID_TTYOU);
1267 acquire_output_mutex (mutex_timeout);
1268 if (!process_opost_output (get_output_handle (), ptr, towrite, false,
1269 get_ttyp (), is_nonblocking ()))
1271 DWORD err = GetLastError ();
1272 termios_printf ("WriteFile failed, %E");
1273 switch (err)
1275 case ERROR_NO_DATA:
1276 err = ERROR_IO_DEVICE;
1277 fallthrough;
1278 default:
1279 __seterrno_from_win_error (err);
1281 towrite = -1;
1283 release_output_mutex ();
1285 return towrite;
1288 /* This function is called from some slave pty reading functions
1289 to switch active pipe to cygwin pipe (not nat pipe) temporarily
1290 even though there is another process which owns nat pipe. This
1291 is needed if cygwin process reads input while another non-cygwin
1292 process is running at the same time.
1293 (e.g. Something like "cat | non-cygwin-app") */
1294 void
1295 fhandler_pty_slave::mask_switch_to_nat_pipe (bool mask, bool xfer)
1297 char name[MAX_PATH];
1298 shared_name (name, TTY_SLAVE_READING, get_minor ());
1299 HANDLE masked = OpenEvent (READ_CONTROL, FALSE, name);
1300 CloseHandle (masked);
1302 WaitForSingleObject (input_mutex, mutex_timeout);
1303 if (mask)
1305 if (InterlockedIncrement (&num_reader) == 1)
1306 slave_reading = CreateEvent (&sec_none_nih, TRUE, FALSE, name);
1308 else if (InterlockedDecrement (&num_reader) == 0)
1309 CloseHandle (slave_reading);
1311 if (!!masked != mask && xfer && get_ttyp ()->switch_to_nat_pipe)
1313 if (mask && get_ttyp ()->pty_input_state_eq (tty::to_nat))
1315 acquire_attach_mutex (mutex_timeout);
1316 transfer_input (tty::to_cyg, get_handle_nat (), get_ttyp (),
1317 input_available_event);
1318 release_attach_mutex ();
1320 else if (!mask && get_ttyp ()->pty_input_state_eq (tty::to_cyg))
1322 acquire_attach_mutex (mutex_timeout);
1323 transfer_input (tty::to_nat, get_handle (), get_ttyp (),
1324 input_available_event);
1325 release_attach_mutex ();
1328 ReleaseMutex (input_mutex);
1331 /* Return true when the non-cygwin app is reading the input. */
1332 bool
1333 fhandler_pty_common::to_be_read_from_nat_pipe (void)
1335 if (!get_ttyp ()->switch_to_nat_pipe)
1336 return false;
1338 char name[MAX_PATH];
1339 shared_name (name, TTY_SLAVE_READING, get_minor ());
1340 HANDLE masked = OpenEvent (READ_CONTROL, FALSE, name);
1341 CloseHandle (masked);
1343 if (masked) /* The foreground process is cygwin process */
1344 return false;
1346 if (!pinfo (get_ttyp ()->getpgid ()))
1347 /* GDB may set invalid process group for non-cygwin process. */
1348 return true;
1350 return get_ttyp ()->nat_fg (get_ttyp ()->getpgid ());
1353 void
1354 fhandler_pty_slave::read (void *ptr, size_t& len)
1356 ssize_t totalread = 0;
1357 int vmin = 0;
1358 int vtime = 0; /* Initialized to prevent -Wuninitialized warning */
1359 size_t readlen;
1360 DWORD bytes_in_pipe;
1361 char buf[INP_BUFFER_SIZE];
1362 DWORD time_to_wait;
1363 char *ptr0 = (char *) ptr;
1365 bg_check_types bg = bg_check (SIGTTIN);
1366 if (bg <= bg_eof)
1368 len = (size_t) bg;
1369 return;
1372 termios_printf ("read(%p, %lu) handle %p", ptr, len, get_handle ());
1374 push_process_state process_state (PID_TTYIN);
1376 if (ptr) /* Indicating not tcflush(). */
1377 mask_switch_to_nat_pipe (true, true);
1379 if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
1380 time_to_wait = 0;
1381 else if ((get_ttyp ()->ti.c_lflag & ICANON))
1382 time_to_wait = INFINITE;
1383 else
1385 vmin = get_ttyp ()->ti.c_cc[VMIN];
1386 if (vmin > INP_BUFFER_SIZE)
1387 vmin = INP_BUFFER_SIZE;
1388 vtime = get_ttyp ()->ti.c_cc[VTIME];
1389 if (vmin < 0)
1390 vmin = 0;
1391 if (vtime < 0)
1392 vtime = 0;
1393 if (!vmin && !vtime)
1394 time_to_wait = 0;
1395 else
1396 time_to_wait = !vtime ? INFINITE : 100 * vtime;
1399 wait_retry:
1400 while (len)
1402 switch (cygwait (input_available_event, time_to_wait))
1404 case WAIT_OBJECT_0:
1405 break;
1406 case WAIT_SIGNALED:
1407 if (totalread > 0)
1408 goto out;
1409 termios_printf ("wait catched signal");
1410 set_sig_errno (EINTR);
1411 totalread = -1;
1412 goto out;
1413 case WAIT_CANCELED:
1414 process_state.pop ();
1415 pthread::static_cancel_self ();
1416 /*NOTREACHED*/
1417 case WAIT_TIMEOUT:
1418 termios_printf ("wait timed out, time_to_wait %u", time_to_wait);
1419 /* No error condition when called from tcflush. */
1420 if (!totalread && ptr)
1422 set_sig_errno (EAGAIN);
1423 totalread = -1;
1425 goto out;
1426 default:
1427 termios_printf ("wait for input event failed, %E");
1428 if (!totalread)
1430 __seterrno ();
1431 totalread = -1;
1433 goto out;
1435 /* Now that we know that input is available we have to grab the
1436 input mutex. */
1437 switch (cygwait (input_mutex, 1000))
1439 case WAIT_OBJECT_0:
1440 case WAIT_ABANDONED_0:
1441 break;
1442 case WAIT_SIGNALED:
1443 if (totalread > 0)
1444 goto out;
1445 termios_printf ("wait for mutex caught signal");
1446 set_sig_errno (EINTR);
1447 totalread = -1;
1448 goto out;
1449 case WAIT_CANCELED:
1450 process_state.pop ();
1451 pthread::static_cancel_self ();
1452 /*NOTREACHED*/
1453 case WAIT_TIMEOUT:
1454 termios_printf ("failed to acquire input mutex after input event "
1455 "arrived");
1456 /* If we have a timeout, we can simply handle this failure to
1457 grab the mutex as an EAGAIN situation. Otherwise, if this
1458 is an infinitely blocking read, restart the loop. */
1459 if (time_to_wait != INFINITE)
1461 if (!totalread)
1463 set_sig_errno (EAGAIN);
1464 totalread = -1;
1466 goto out;
1468 continue;
1469 default:
1470 termios_printf ("wait for input mutex failed, %E");
1471 if (!totalread)
1473 __seterrno ();
1474 totalread = -1;
1476 goto out;
1478 if (!IsEventSignalled (input_available_event))
1479 { /* Maybe another thread has processed input. */
1480 ReleaseMutex (input_mutex);
1481 goto wait_retry;
1484 if (!bytes_available (bytes_in_pipe))
1486 ReleaseMutex (input_mutex);
1487 set_errno (EIO);
1488 totalread = -1;
1489 goto out;
1492 if (ptr && !bytes_in_pipe && !vmin && !time_to_wait)
1494 ReleaseMutex (input_mutex);
1495 mask_switch_to_nat_pipe (false, false);
1496 len = (size_t) bytes_in_pipe;
1497 return;
1500 readlen = bytes_in_pipe ? MIN (len, sizeof (buf)) : 0;
1501 if (get_ttyp ()->ti.c_lflag & ICANON && ptr)
1502 readlen = MIN (bytes_in_pipe, readlen);
1504 #if 0
1505 /* Why on earth is the read length reduced to vmin, even if more bytes
1506 are available *and* len is bigger *and* the local buf is big enough?
1507 Disable this code for now, it looks like a remnant of old. */
1508 if (ptr && vmin && readlen > (unsigned) vmin)
1509 readlen = vmin;
1510 #endif
1512 DWORD n = 0;
1513 if (readlen)
1515 termios_printf ("reading %lu bytes (vtime %d)", readlen, vtime);
1516 if (!ReadFile (get_handle (), buf, readlen, &n, NULL))
1518 termios_printf ("read failed, %E");
1519 ReleaseMutex (input_mutex);
1520 set_errno (EIO);
1521 totalread = -1;
1522 goto out;
1524 else
1526 /* MSDN states that 5th prameter can be used to determine total
1527 number of bytes in pipe, but for some reason this number doesn't
1528 change after successful read. So we have to peek into the pipe
1529 again to see if input is still available */
1530 if (!bytes_available (bytes_in_pipe))
1532 ReleaseMutex (input_mutex);
1533 set_errno (EIO);
1534 totalread = -1;
1535 goto out;
1537 if (n)
1539 if (!(!ptr && len == UINT_MAX)) /* not tcflush() */
1540 len -= n;
1541 totalread += n;
1542 if (ptr)
1544 memcpy (ptr, buf, n);
1545 ptr = (char *) ptr + n;
1551 if (!bytes_in_pipe)
1552 ResetEvent (input_available_event);
1554 ReleaseMutex (input_mutex);
1556 if (!ptr)
1558 if (!bytes_in_pipe)
1559 break;
1560 continue;
1563 if (get_ttyp ()->read_retval < 0) // read error
1565 set_errno (-get_ttyp ()->read_retval);
1566 totalread = -1;
1567 break;
1569 if (get_ttyp ()->read_retval == 0) //EOF
1571 termios_printf ("saw EOF");
1572 break;
1574 if (get_ttyp ()->ti.c_lflag & ICANON || is_nonblocking ())
1575 break;
1576 if (vmin && totalread >= vmin)
1577 break;
1579 /* vmin == 0 && vtime == 0:
1580 * we've already read all input, if any, so return immediately
1581 * vmin == 0 && vtime > 0:
1582 * we've waited for input 10*vtime ms in WFSO(input_available_event),
1583 * no matter whether any input arrived, we shouldn't wait any longer,
1584 * so return immediately
1585 * vmin > 0 && vtime == 0:
1586 * here, totalread < vmin, so continue waiting until more data
1587 * arrive
1588 * vmin > 0 && vtime > 0:
1589 * similar to the previous here, totalread < vmin, and timer
1590 * hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT,
1591 * so "restart timer" and wait until more data arrive
1594 if (vmin == 0)
1595 break;
1597 out:
1598 termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
1599 len = (size_t) totalread;
1600 if (ptr0)
1601 { /* Not tcflush() */
1602 bool saw_eol = totalread > 0 && strchr ("\r\n", ptr0[totalread -1]);
1603 mask_switch_to_nat_pipe (false, saw_eol || len == 0);
1608 fhandler_pty_slave::dup (fhandler_base *child, int flags)
1610 /* This code was added in Oct 2001 for some undisclosed reason.
1611 However, setting the controlling tty on a dup causes rxvt to
1612 hang when the parent does a dup since the controlling pgid changes.
1613 Specifically testing for CTTY_RELEASED (ctty has been setsid'ed)
1614 works around this problem. However, it's difficult to see scenarios
1615 in which you have a dup'able fd, no controlling tty, and not having
1616 run setsid. So, we might want to consider getting rid of the
1617 set_ctty in tty-like dup methods entirely at some point */
1618 if (myself->ctty != CTTY_RELEASED)
1619 myself->set_ctty (this, flags);
1620 report_tty_counts (child, "duped slave", "");
1621 return 0;
1625 fhandler_pty_master::dup (fhandler_base *child, int)
1627 report_tty_counts (child, "duped master", "");
1628 return 0;
1632 fhandler_pty_slave::tcgetattr (struct termios *t)
1634 *t = get_ttyp ()->ti;
1636 /* Workaround for rlwrap */
1637 cygheap_fdenum cfd (false);
1638 while (cfd.next () >= 0)
1639 if (cfd->get_major () == DEV_PTYM_MAJOR
1640 && cfd->get_minor () == get_minor ())
1642 if (get_ttyp ()->pcon_start)
1643 t->c_lflag &= ~(ICANON | ECHO);
1644 if (get_ttyp ()->pcon_activated)
1645 t->c_iflag &= ~ICRNL;
1646 break;
1648 return 0;
1652 fhandler_pty_slave::tcsetattr (int, const struct termios *t)
1654 acquire_output_mutex (mutex_timeout);
1655 get_ttyp ()->ti = *t;
1656 release_output_mutex ();
1657 return 0;
1661 fhandler_pty_slave::tcflush (int queue)
1663 int ret = 0;
1665 termios_printf ("tcflush(%d) handle %p", queue, get_handle ());
1667 if (queue == TCIFLUSH || queue == TCIOFLUSH)
1669 size_t len = UINT_MAX;
1670 read (NULL, len);
1671 ret = ((int) len) >= 0 ? 0 : -1;
1673 if (queue == TCOFLUSH || queue == TCIOFLUSH)
1675 /* do nothing for now. */
1678 termios_printf ("%d=tcflush(%d)", ret, queue);
1679 return ret;
1683 fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
1685 termios_printf ("ioctl (%x)", cmd);
1686 int res = fhandler_termios::ioctl (cmd, arg);
1687 if (res <= 0)
1688 return res;
1690 if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid
1691 && (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ())
1692 && (get_ttyp ()->ti.c_lflag & TOSTOP))
1694 /* background process */
1695 termios_printf ("bg ioctl pgid %d, tpgid %d, %s", myself->pgid,
1696 get_ttyp ()->getpgid (), myctty ());
1697 raise (SIGTTOU);
1700 int retval;
1701 switch (cmd)
1703 case TIOCGWINSZ:
1704 case TIOCSWINSZ:
1705 break;
1706 case TIOCGPGRP:
1708 pid_t pid = this->tcgetpgrp ();
1709 if (pid < 0)
1710 retval = -1;
1711 else
1713 *((pid_t *) arg) = pid;
1714 retval = 0;
1717 goto out;
1718 case TIOCSPGRP:
1719 retval = this->tcsetpgrp ((pid_t) (intptr_t) arg);
1720 goto out;
1721 case FIONREAD:
1723 DWORD n;
1724 if (!bytes_available (n))
1726 set_errno (EINVAL);
1727 retval = -1;
1729 else
1731 *(int *) arg = (int) n;
1732 retval = 0;
1735 goto out;
1736 default:
1737 return fhandler_base::ioctl (cmd, arg);
1740 acquire_output_mutex (mutex_timeout);
1742 get_ttyp ()->cmd = cmd;
1743 get_ttyp ()->ioctl_retval = 0;
1744 switch (cmd)
1746 case TIOCGWINSZ:
1747 get_ttyp ()->arg.winsize = get_ttyp ()->winsize;
1748 *(struct winsize *) arg = get_ttyp ()->arg.winsize;
1749 get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
1750 break;
1751 case TIOCSWINSZ:
1752 if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
1753 || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col
1754 || get_ttyp ()->winsize.ws_ypixel != ((struct winsize *) arg)->ws_ypixel
1755 || get_ttyp ()->winsize.ws_xpixel != ((struct winsize *) arg)->ws_xpixel
1758 if (get_ttyp ()->pcon_activated && get_ttyp ()->nat_pipe_owner_pid)
1759 resize_pseudo_console ((struct winsize *) arg);
1760 get_ttyp ()->arg.winsize = *(struct winsize *) arg;
1761 get_ttyp ()->winsize = *(struct winsize *) arg;
1762 get_ttyp ()->kill_pgrp (SIGWINCH);
1764 break;
1767 release_output_mutex ();
1768 retval = get_ttyp ()->ioctl_retval;
1769 if (retval < 0)
1771 set_errno (-retval);
1772 retval = -1;
1775 out:
1776 termios_printf ("%d = ioctl(%x)", retval, cmd);
1777 return retval;
1781 fhandler_pty_slave::fstat (struct stat *st)
1783 fhandler_termios::fstat (st);
1785 bool to_close = false;
1786 if (!input_available_event)
1788 char buf[MAX_PATH];
1789 shared_name (buf, INPUT_AVAILABLE_EVENT, get_minor ());
1790 input_available_event = OpenEvent (READ_CONTROL, TRUE, buf);
1791 if (input_available_event)
1792 to_close = true;
1794 st->st_mode = S_IFCHR;
1795 if (!input_available_event
1796 || get_object_attribute (input_available_event, &st->st_uid, &st->st_gid,
1797 st->st_mode))
1799 /* If we can't access the ACL, or if the tty doesn't actually exist,
1800 then fake uid and gid to strict, system-like values. */
1801 st->st_mode = S_IFCHR | S_IRUSR | S_IWUSR;
1802 st->st_uid = 18;
1803 st->st_gid = 544;
1805 if (to_close)
1806 CloseHandle (input_available_event);
1807 return 0;
1811 fhandler_pty_slave::facl (int cmd, int nentries, aclent_t *aclbufp)
1813 int res = -1;
1814 bool to_close = false;
1815 security_descriptor sd;
1816 mode_t attr = S_IFCHR;
1818 switch (cmd)
1820 case SETACL:
1821 if (!aclsort (nentries, 0, aclbufp))
1822 set_errno (ENOTSUP);
1823 break;
1824 case GETACL:
1825 if (!aclbufp)
1827 set_errno (EFAULT);
1828 break;
1830 fallthrough;
1831 case GETACLCNT:
1832 if (!input_available_event)
1834 char buf[MAX_PATH];
1835 shared_name (buf, INPUT_AVAILABLE_EVENT, get_minor ());
1836 input_available_event = OpenEvent (READ_CONTROL, TRUE, buf);
1837 if (input_available_event)
1838 to_close = true;
1840 if (!input_available_event
1841 || get_object_sd (input_available_event, sd))
1843 res = get_posix_access (NULL, attr, NULL, NULL, aclbufp, nentries);
1844 if (aclbufp && res == MIN_ACL_ENTRIES)
1846 aclbufp[0].a_perm = S_IROTH | S_IWOTH;
1847 aclbufp[0].a_id = 18;
1848 aclbufp[1].a_id = 544;
1850 break;
1852 if (cmd == GETACL)
1853 res = get_posix_access (sd, attr, NULL, NULL, aclbufp, nentries);
1854 else
1855 res = get_posix_access (sd, attr, NULL, NULL, NULL, 0);
1856 break;
1857 default:
1858 set_errno (EINVAL);
1859 break;
1861 if (to_close)
1862 CloseHandle (input_available_event);
1863 return res;
1866 /* Helper function for fchmod and fchown, which just opens all handles
1867 and signals success via bool return. */
1868 bool
1869 fhandler_pty_slave::fch_open_handles (bool chown)
1871 char buf[MAX_PATH];
1872 DWORD write_access = WRITE_DAC | (chown ? WRITE_OWNER : 0);
1874 _tc = cygwin_shared->tty[get_minor ()];
1875 shared_name (buf, INPUT_AVAILABLE_EVENT, get_minor ());
1876 input_available_event = OpenEvent (READ_CONTROL | write_access,
1877 TRUE, buf);
1878 output_mutex = get_ttyp ()->open_output_mutex (write_access);
1879 input_mutex = get_ttyp ()->open_input_mutex (write_access);
1880 pipe_sw_mutex = get_ttyp ()->open_mutex (PIPE_SW_MUTEX, write_access);
1881 inuse = get_ttyp ()->open_inuse (write_access);
1882 if (!input_available_event || !output_mutex || !input_mutex || !inuse)
1884 __seterrno ();
1885 return false;
1887 return true;
1890 /* Helper function for fchmod and fchown, which sets the new security
1891 descriptor on all objects representing the pty. */
1893 fhandler_pty_slave::fch_set_sd (security_descriptor &sd, bool chown)
1895 security_descriptor sd_old;
1897 get_object_sd (input_available_event, sd_old);
1898 if (!set_object_sd (input_available_event, sd, chown)
1899 && !set_object_sd (output_mutex, sd, chown)
1900 && !set_object_sd (input_mutex, sd, chown)
1901 && !set_object_sd (inuse, sd, chown))
1902 return 0;
1903 set_object_sd (input_available_event, sd_old, chown);
1904 set_object_sd (output_mutex, sd_old, chown);
1905 set_object_sd (input_mutex, sd_old, chown);
1906 set_object_sd (inuse, sd_old, chown);
1907 return -1;
1910 /* Helper function for fchmod and fchown, which closes all object handles in
1911 the pty. */
1912 void
1913 fhandler_pty_slave::fch_close_handles ()
1915 close_maybe (input_available_event);
1916 close_maybe (output_mutex);
1917 close_maybe (input_mutex);
1918 close_maybe (inuse);
1922 fhandler_pty_slave::fchmod (mode_t mode)
1924 int ret = -1;
1925 bool to_close = false;
1926 security_descriptor sd;
1927 uid_t uid;
1928 gid_t gid;
1929 mode_t orig_mode = S_IFCHR;
1931 if (!input_available_event)
1933 to_close = true;
1934 if (!fch_open_handles (false))
1935 goto errout;
1937 sd.malloc (sizeof (SECURITY_DESCRIPTOR));
1938 RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
1939 if (!get_object_attribute (input_available_event, &uid, &gid, orig_mode)
1940 && !create_object_sd_from_attribute (uid, gid, S_IFCHR | mode, sd))
1941 ret = fch_set_sd (sd, false);
1942 errout:
1943 if (to_close)
1944 fch_close_handles ();
1945 return ret;
1949 fhandler_pty_slave::fchown (uid_t uid, gid_t gid)
1951 int ret = -1;
1952 bool to_close = false;
1953 security_descriptor sd;
1954 uid_t o_uid;
1955 gid_t o_gid;
1956 mode_t mode = S_IFCHR;
1958 if (uid == ILLEGAL_UID && gid == ILLEGAL_GID)
1959 return 0;
1960 if (!input_available_event)
1962 to_close = true;
1963 if (!fch_open_handles (true))
1964 goto errout;
1966 sd.malloc (sizeof (SECURITY_DESCRIPTOR));
1967 RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
1968 if (!get_object_attribute (input_available_event, &o_uid, &o_gid, mode))
1970 if (uid == ILLEGAL_UID)
1971 uid = o_uid;
1972 if (gid == ILLEGAL_GID)
1973 gid = o_gid;
1974 if (uid == o_uid && gid == o_gid)
1975 ret = 0;
1976 else if (!create_object_sd_from_attribute (uid, gid, mode, sd))
1977 ret = fch_set_sd (sd, true);
1979 errout:
1980 if (to_close)
1981 fch_close_handles ();
1982 return ret;
1985 /*******************************************************
1986 fhandler_pty_master
1988 fhandler_pty_master::fhandler_pty_master (int unit, dev_t via)
1989 : fhandler_pty_common (), pktmode (0), master_ctl (NULL),
1990 master_thread (NULL), from_master_nat (NULL), to_master_nat (NULL),
1991 from_slave_nat (NULL), to_slave_nat (NULL), echo_r (NULL), echo_w (NULL),
1992 dwProcessId (0), to_master (NULL), from_master (NULL),
1993 master_fwd_thread (NULL)
1995 dev_referred_via = via;
1996 if (unit >= 0)
1997 dev ().parse (DEV_PTYM_MAJOR, unit);
1998 set_name ("/dev/ptmx");
2002 fhandler_pty_master::open (int flags, mode_t)
2004 if (!setup ())
2005 return 0;
2006 set_open_status ();
2007 dwProcessId = GetCurrentProcessId ();
2008 return 1;
2011 bool
2012 fhandler_pty_master::open_setup (int flags)
2014 set_flags ((flags & ~O_TEXT) | O_BINARY);
2015 char buf[sizeof ("opened pty master for ptyNNNNNNNNNNN")];
2016 __small_sprintf (buf, "opened pty master for pty%d", get_minor ());
2017 report_tty_counts (this, buf, "");
2018 return fhandler_base::open_setup (flags);
2021 off_t
2022 fhandler_pty_common::lseek (off_t, int)
2024 set_errno (ESPIPE);
2025 return -1;
2029 fhandler_pty_common::close ()
2031 termios_printf ("pty%d <%p,%p> closing",
2032 get_minor (), get_handle (), get_output_handle ());
2033 if (!ForceCloseHandle (input_mutex))
2034 termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex);
2035 if (!ForceCloseHandle (pipe_sw_mutex))
2036 termios_printf ("CloseHandle (pipe_sw_mutex<%p>), %E", pipe_sw_mutex);
2037 if (!ForceCloseHandle1 (get_handle (), from_pty))
2038 termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ());
2039 if (!ForceCloseHandle1 (get_output_handle (), to_pty))
2040 termios_printf ("CloseHandle (get_output_handle ()<%p>), %E",
2041 get_output_handle ());
2043 return 0;
2046 void
2047 fhandler_pty_common::resize_pseudo_console (struct winsize *ws)
2049 COORD size;
2050 size.X = ws->ws_col;
2051 size.Y = ws->ws_row;
2052 HPCON_INTERNAL hpcon_local;
2053 HANDLE pcon_owner =
2054 OpenProcess (PROCESS_DUP_HANDLE, FALSE, get_ttyp ()->nat_pipe_owner_pid);
2055 DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
2056 GetCurrentProcess (), &hpcon_local.hWritePipe,
2057 0, FALSE, DUPLICATE_SAME_ACCESS);
2058 acquire_attach_mutex (mutex_timeout);
2059 ResizePseudoConsole ((HPCON) &hpcon_local, size);
2060 release_attach_mutex ();
2061 CloseHandle (pcon_owner);
2062 CloseHandle (hpcon_local.hWritePipe);
2065 void
2066 fhandler_pty_master::cleanup ()
2068 report_tty_counts (this, "closing master", "");
2069 if (archetype)
2070 from_master_nat = from_master =
2071 to_master_nat = to_master = from_slave_nat = to_slave_nat = NULL;
2072 fhandler_base::cleanup ();
2076 fhandler_pty_master::close ()
2078 OBJECT_BASIC_INFORMATION obi;
2079 NTSTATUS status;
2081 termios_printf ("closing from_master_nat(%p)/from_master(%p)/to_master_nat(%p)/to_master(%p) since we own them(%u)",
2082 from_master_nat, from_master,
2083 to_master_nat, to_master, dwProcessId);
2084 if (cygwin_finished_initializing)
2086 if (master_ctl && get_ttyp ()->master_pid == myself->pid)
2088 char buf[MAX_PATH];
2089 pipe_request req = { (DWORD) -1 };
2090 pipe_reply repl;
2091 DWORD len;
2093 __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
2094 &cygheap->installation_key, get_minor ());
2095 acquire_output_mutex (mutex_timeout);
2096 if (master_ctl)
2098 CallNamedPipe (buf, &req, sizeof req, &repl, sizeof repl, &len,
2099 500);
2100 CloseHandle (master_ctl);
2101 master_thread->detach ();
2102 get_ttyp ()->set_master_ctl_closed ();
2103 master_ctl = NULL;
2105 release_output_mutex ();
2106 get_ttyp ()->stop_fwd_thread = true;
2107 WriteFile (to_master_nat, "", 0, &len, NULL);
2108 master_fwd_thread->detach ();
2109 if (helper_goodbye)
2111 SetEvent (helper_goodbye);
2112 WaitForSingleObject (helper_h_process, INFINITE);
2113 CloseHandle (helper_h_process);
2114 CloseHandle (helper_goodbye);
2115 helper_h_process = 0;
2116 helper_goodbye = NULL;
2121 /* Check if the last master handle has been closed. If so, set
2122 input_available_event to wake up potentially waiting slaves. */
2123 acquire_output_mutex (mutex_timeout);
2124 status = NtQueryObject (get_output_handle (), ObjectBasicInformation,
2125 &obi, sizeof obi, NULL);
2126 fhandler_pty_common::close ();
2127 release_output_mutex ();
2128 if (!ForceCloseHandle (output_mutex))
2129 termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
2130 if (!NT_SUCCESS (status))
2131 debug_printf ("NtQueryObject: %y", status);
2132 else if (obi.HandleCount == 1)
2134 termios_printf ("Closing last master of pty%d", get_minor ());
2135 if (get_ttyp ()->getsid () > 0)
2136 kill (get_ttyp ()->getsid (), SIGHUP);
2137 SetEvent (input_available_event);
2140 if (!ForceCloseHandle (from_master_nat))
2141 termios_printf ("error closing from_master_nat %p, %E", from_master_nat);
2142 if (!ForceCloseHandle (to_master_nat))
2143 termios_printf ("error closing to_master_nat %p, %E", to_master_nat);
2144 from_master_nat = to_master_nat = NULL;
2145 if (!ForceCloseHandle (from_slave_nat))
2146 termios_printf ("error closing from_slave_nat %p, %E", from_slave_nat);
2147 from_slave_nat = NULL;
2148 if (!ForceCloseHandle (to_master))
2149 termios_printf ("error closing to_master %p, %E", to_master);
2150 to_master = NULL;
2151 ForceCloseHandle (echo_r);
2152 ForceCloseHandle (echo_w);
2153 echo_r = echo_w = NULL;
2154 if (to_slave_nat)
2155 ForceCloseHandle (to_slave_nat);
2156 to_slave_nat = NULL;
2158 if (have_execed || get_ttyp ()->master_pid != myself->pid)
2159 termios_printf ("not clearing: %d, master_pid %d",
2160 have_execed, get_ttyp ()->master_pid);
2161 if (!ForceCloseHandle (input_available_event))
2162 termios_printf ("CloseHandle (input_available_event<%p>), %E",
2163 input_available_event);
2165 /* The from_master must be closed last so that the same pty is not
2166 allocated before cleaning up the other corresponding instances. */
2167 if (!ForceCloseHandle (from_master))
2168 termios_printf ("error closing from_master %p, %E", from_master);
2169 from_master = NULL;
2171 return 0;
2174 ssize_t
2175 fhandler_pty_master::write (const void *ptr, size_t len)
2177 ssize_t ret;
2178 char *p = (char *) ptr;
2179 termios &ti = tc ()->ti;
2181 bg_check_types bg = bg_check (SIGTTOU);
2182 if (bg <= bg_eof)
2183 return (ssize_t) bg;
2185 push_process_state process_state (PID_TTYOU);
2187 if (get_ttyp ()->pcon_start)
2188 { /* Reaches here when pseudo console initialization is on going. */
2189 /* Pseudo condole support uses "CSI6n" to get cursor position.
2190 If the reply for "CSI6n" is divided into multiple writes,
2191 pseudo console sometimes does not recognize it. Therefore,
2192 put them together into wpbuf and write all at once. */
2193 static const int wpbuf_len = strlen ("\033[32768;32868R");
2194 static char wpbuf[wpbuf_len];
2195 static int ixput = 0;
2196 static int state = 0;
2198 DWORD n;
2199 WaitForSingleObject (input_mutex, mutex_timeout);
2200 for (size_t i = 0; i < len; i++)
2202 if (p[i] == '\033')
2204 if (ixput)
2205 line_edit (wpbuf, ixput, ti, &ret);
2206 ixput = 0;
2207 state = 1;
2209 if (state == 1)
2211 if (ixput < wpbuf_len)
2212 wpbuf[ixput++] = p[i];
2213 else
2215 if (!get_ttyp ()->req_xfer_input)
2216 WriteFile (to_slave_nat, wpbuf, ixput, &n, NULL);
2217 ixput = 0;
2218 wpbuf[ixput++] = p[i];
2221 else
2222 line_edit (p + i, 1, ti, &ret);
2223 if (state == 1 && p[i] == 'R')
2224 state = 2;
2226 if (state == 2)
2228 /* req_xfer_input is true if "ESC[6n" was sent just for
2229 triggering transfer_input() in master. In this case,
2230 the responce sequence should not be written. */
2231 if (!get_ttyp ()->req_xfer_input)
2232 WriteFile (to_slave_nat, wpbuf, ixput, &n, NULL);
2233 ixput = 0;
2234 state = 0;
2235 get_ttyp ()->req_xfer_input = false;
2236 get_ttyp ()->pcon_start = false;
2238 ReleaseMutex (input_mutex);
2240 if (!get_ttyp ()->pcon_start)
2241 { /* Pseudo console initialization has been done in above code. */
2242 pinfo pp (get_ttyp ()->pcon_start_pid);
2243 if (get_ttyp ()->switch_to_nat_pipe
2244 && get_ttyp ()->pty_input_state_eq (tty::to_cyg))
2246 /* This accept_input() call is needed in order to transfer input
2247 which is not accepted yet to non-cygwin pipe. */
2248 WaitForSingleObject (input_mutex, mutex_timeout);
2249 if (get_readahead_valid ())
2250 accept_input ();
2251 acquire_attach_mutex (mutex_timeout);
2252 fhandler_pty_slave::transfer_input (tty::to_nat, from_master,
2253 get_ttyp (),
2254 input_available_event);
2255 release_attach_mutex ();
2256 ReleaseMutex (input_mutex);
2258 get_ttyp ()->pcon_start_pid = 0;
2261 return len;
2264 /* Write terminal input to to_slave_nat pipe instead of output_handle
2265 if current application is native console application. */
2266 WaitForSingleObject (input_mutex, mutex_timeout);
2267 if (to_be_read_from_nat_pipe () && get_ttyp ()->pcon_activated
2268 && get_ttyp ()->pty_input_state == tty::to_nat)
2269 { /* Reaches here when non-cygwin app is foreground and pseudo console
2270 is activated. */
2271 tmp_pathbuf tp;
2272 char *buf = (char *) ptr;
2273 size_t nlen = len;
2274 if (get_ttyp ()->term_code_page != CP_UTF8)
2276 static mbstate_t mbp;
2277 buf = tp.c_get ();
2278 nlen = NT_MAX_PATH;
2279 convert_mb_str (CP_UTF8, buf, &nlen,
2280 get_ttyp ()->term_code_page, (const char *) ptr, len,
2281 &mbp);
2284 for (size_t i = 0; i < nlen; i++)
2286 process_sig_state r = process_sigs (buf[i], get_ttyp (), this);
2287 if (r == done_with_debugger)
2289 for (size_t j = i; j < nlen - 1; j++)
2290 buf[j] = buf[j + 1];
2291 nlen--;
2292 i--;
2294 process_stop_start (buf[i], get_ttyp ());
2297 DWORD n;
2298 WriteFile (to_slave_nat, buf, nlen, &n, NULL);
2299 ReleaseMutex (input_mutex);
2301 return len;
2304 /* The code path reaches here when pseudo console is not activated
2305 or cygwin process is foreground even though pseudo console is
2306 activated. */
2308 /* This input transfer is needed when cygwin-app which is started from
2309 non-cygwin app is terminated if pseudo console is disabled. */
2310 if (to_be_read_from_nat_pipe () && !get_ttyp ()->pcon_activated
2311 && get_ttyp ()->pty_input_state == tty::to_cyg)
2313 acquire_attach_mutex (mutex_timeout);
2314 fhandler_pty_slave::transfer_input (tty::to_nat, from_master,
2315 get_ttyp (), input_available_event);
2316 release_attach_mutex ();
2319 line_edit_status status = line_edit (p, len, ti, &ret);
2320 ReleaseMutex (input_mutex);
2322 if (status > line_edit_signalled && status != line_edit_pipe_full)
2323 ret = -1;
2324 return ret;
2327 void
2328 fhandler_pty_master::read (void *ptr, size_t& len)
2330 bg_check_types bg = bg_check (SIGTTIN);
2331 if (bg <= bg_eof)
2333 len = (size_t) bg;
2334 return;
2336 push_process_state process_state (PID_TTYIN);
2337 len = (size_t) process_slave_output ((char *) ptr, len, pktmode);
2341 fhandler_pty_master::tcgetattr (struct termios *t)
2343 *t = cygwin_shared->tty[get_minor ()]->ti;
2344 /* Workaround for rlwrap v0.40 or later */
2345 if (get_ttyp ()->pcon_start)
2346 t->c_lflag &= ~(ICANON | ECHO);
2347 if (get_ttyp ()->pcon_activated)
2348 t->c_iflag &= ~ICRNL;
2349 return 0;
2353 fhandler_pty_master::tcsetattr (int, const struct termios *t)
2355 cygwin_shared->tty[get_minor ()]->ti = *t;
2356 return 0;
2360 fhandler_pty_master::tcflush (int queue)
2362 int ret = 0;
2364 termios_printf ("tcflush(%d) handle %p", queue, get_handle ());
2366 if (queue == TCIFLUSH || queue == TCIOFLUSH)
2367 ret = process_slave_output (NULL, OUT_BUFFER_SIZE, 0);
2368 if (queue == TCOFLUSH || queue == TCIOFLUSH)
2370 /* do nothing for now. */
2373 termios_printf ("%d=tcflush(%d)", ret, queue);
2374 return ret;
2378 fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
2380 int res = fhandler_termios::ioctl (cmd, arg);
2381 if (res <= 0)
2382 return res;
2384 switch (cmd)
2386 case TIOCPKT:
2387 pktmode = *(int *) arg;
2388 break;
2389 case TIOCGWINSZ:
2390 *(struct winsize *) arg = get_ttyp ()->winsize;
2391 break;
2392 case TIOCSWINSZ:
2393 if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
2394 || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col
2395 || get_ttyp ()->winsize.ws_ypixel != ((struct winsize *) arg)->ws_ypixel
2396 || get_ttyp ()->winsize.ws_xpixel != ((struct winsize *) arg)->ws_xpixel
2399 if (get_ttyp ()->pcon_activated && get_ttyp ()->nat_pipe_owner_pid)
2400 resize_pseudo_console ((struct winsize *) arg);
2401 get_ttyp ()->winsize = *(struct winsize *) arg;
2402 get_ttyp ()->kill_pgrp (SIGWINCH);
2404 break;
2405 case TIOCGPGRP:
2406 *((pid_t *) arg) = this->tcgetpgrp ();
2407 break;
2408 case TIOCSPGRP:
2409 return this->tcsetpgrp ((pid_t) (intptr_t) arg);
2410 case FIONREAD:
2412 DWORD n;
2413 if (!bytes_available (n))
2415 set_errno (EINVAL);
2416 return -1;
2418 *(int *) arg = (int) n;
2420 break;
2421 default:
2422 return fhandler_base::ioctl (cmd, arg);
2424 return 0;
2428 fhandler_pty_master::ptsname_r (char *buf, size_t buflen)
2430 char tmpbuf[TTY_NAME_MAX];
2432 __ptsname (tmpbuf, get_minor ());
2433 if (buflen <= strlen (tmpbuf))
2435 set_errno (ERANGE);
2436 return ERANGE;
2438 strcpy (buf, tmpbuf);
2439 return 0;
2442 void
2443 fhandler_pty_common::set_close_on_exec (bool val)
2445 // Cygwin processes will handle this specially on exec.
2446 close_on_exec (val);
2449 void
2450 fhandler_pty_slave::setup_locale (void)
2452 extern UINT __eval_codepage_from_internal_charset ();
2454 if (!get_ttyp ()->term_code_page)
2456 get_ttyp ()->term_code_page = __eval_codepage_from_internal_charset ();
2457 acquire_attach_mutex (mutex_timeout);
2458 SetConsoleCP (get_ttyp ()->term_code_page);
2459 SetConsoleOutputCP (get_ttyp ()->term_code_page);
2460 release_attach_mutex ();
2464 bg_check_types
2465 fhandler_pty_slave::bg_check (int sig, bool dontsignal)
2467 reset_switch_to_nat_pipe ();
2468 return fhandler_termios::bg_check (sig, dontsignal);
2471 void
2472 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
2474 create_invisible_console ();
2476 // fork_fixup (parent, inuse, "inuse");
2477 // fhandler_pty_common::fixup_after_fork (parent);
2478 report_tty_counts (this, "inherited", "");
2481 void
2482 fhandler_pty_slave::fixup_after_exec ()
2484 if (!close_on_exec ())
2485 fixup_after_fork (NULL); /* No parent handle required. */
2487 /* Hook Console API */
2488 #define DO_HOOK(module, name) \
2489 if (!name##_Orig) \
2491 void *api = hook_api (module, #name, (void *) name##_Hooked); \
2492 name##_Orig = (__typeof__ (name) *) api; \
2493 /*if (api) system_printf (#name " hooked.");*/ \
2495 /* CreateProcess() is hooked for GDB etc. */
2496 DO_HOOK (NULL, CreateProcessA);
2497 DO_HOOK (NULL, CreateProcessW);
2500 /* This thread function handles the master control pipe. It waits for a
2501 client to connect. Then it checks if the client process has permissions
2502 to access the tty handles. If so, it opens the client process and
2503 duplicates the handles into that process. If that fails, it sends a reply
2504 with at least one handle set to NULL and an error code. Last but not
2505 least, the client is disconnected and the thread waits for the next client.
2507 A special case is when the master side of the tty is about to be closed.
2508 The client side is the fhandler_pty_master::close function and it sends
2509 a PID -1 in that case. A check is performed that the request to leave
2510 really comes from the master process itself.
2512 Since there's always only one pipe instance, there's a chance that clients
2513 have to wait to connect to the master control pipe. Therefore the client
2514 calls to CallNamedPipe should have a big enough timeout value. For now this
2515 is 500ms. Hope that's enough. */
2517 /* The function pty_master_thread() should be static because the instance
2518 is deleted if the master is dup()'ed and the original is closed. In
2519 this case, dup()'ed instance still exists, therefore, master thread
2520 is also still alive even though the instance has been deleted. As a
2521 result, accesing member variables in this function causes access
2522 violation. */
2524 DWORD
2525 fhandler_pty_master::pty_master_thread (const master_thread_param_t *p)
2527 bool exit = false;
2528 GENERIC_MAPPING map = { EVENT_QUERY_STATE, EVENT_MODIFY_STATE, 0,
2529 EVENT_QUERY_STATE | EVENT_MODIFY_STATE };
2530 pipe_request req;
2531 DWORD len;
2532 security_descriptor sd;
2533 HANDLE token;
2534 PRIVILEGE_SET ps;
2535 DWORD pid;
2536 NTSTATUS status;
2538 termios_printf ("Entered");
2539 while (!exit && (ConnectNamedPipe (p->master_ctl, NULL)
2540 || GetLastError () == ERROR_PIPE_CONNECTED))
2542 pipe_reply repl = { NULL, NULL, NULL, NULL, NULL, NULL, 0 };
2543 bool deimp = false;
2544 NTSTATUS allow = STATUS_ACCESS_DENIED;
2545 ACCESS_MASK access = EVENT_MODIFY_STATE;
2546 HANDLE client = NULL;
2548 if (!ReadFile (p->master_ctl, &req, sizeof req, &len, NULL))
2550 termios_printf ("ReadFile, %E");
2551 goto reply;
2553 if (!GetNamedPipeClientProcessId (p->master_ctl, &pid))
2554 pid = req.pid;
2555 if (get_object_sd (p->input_available_event, sd))
2557 termios_printf ("get_object_sd, %E");
2558 goto reply;
2560 cygheap->user.deimpersonate ();
2561 deimp = true;
2562 if (!ImpersonateNamedPipeClient (p->master_ctl))
2564 termios_printf ("ImpersonateNamedPipeClient, %E");
2565 goto reply;
2567 status = NtOpenThreadToken (GetCurrentThread (), TOKEN_QUERY, TRUE,
2568 &token);
2569 if (!NT_SUCCESS (status))
2571 termios_printf ("NtOpenThreadToken, %y", status);
2572 SetLastError (RtlNtStatusToDosError (status));
2573 goto reply;
2575 len = sizeof ps;
2576 status = NtAccessCheck (sd, token, access, &map, &ps, &len, &access,
2577 &allow);
2578 NtClose (token);
2579 if (!NT_SUCCESS (status))
2581 termios_printf ("NtAccessCheck, %y", status);
2582 SetLastError (RtlNtStatusToDosError (status));
2583 goto reply;
2585 if (!RevertToSelf ())
2587 termios_printf ("RevertToSelf, %E");
2588 goto reply;
2590 if (req.pid == (DWORD) -1) /* Request to finish thread. */
2592 /* Check if the requesting process is the master process itself. */
2593 if (pid == GetCurrentProcessId ())
2594 exit = true;
2595 goto reply;
2597 if (NT_SUCCESS (allow))
2599 client = OpenProcess (PROCESS_DUP_HANDLE, FALSE, pid);
2600 if (!client)
2602 termios_printf ("OpenProcess, %E");
2603 goto reply;
2605 if (!DuplicateHandle (GetCurrentProcess (), p->from_master_nat,
2606 client, &repl.from_master_nat,
2607 0, TRUE, DUPLICATE_SAME_ACCESS))
2609 termios_printf ("DuplicateHandle (from_master_nat), %E");
2610 goto reply;
2612 if (!DuplicateHandle (GetCurrentProcess (), p->from_master,
2613 client, &repl.from_master,
2614 0, TRUE, DUPLICATE_SAME_ACCESS))
2616 termios_printf ("DuplicateHandle (from_master), %E");
2617 goto reply;
2619 if (!DuplicateHandle (GetCurrentProcess (), p->to_master_nat,
2620 client, &repl.to_master_nat,
2621 0, TRUE, DUPLICATE_SAME_ACCESS))
2623 termios_printf ("DuplicateHandle (to_master_nat), %E");
2624 goto reply;
2626 if (!DuplicateHandle (GetCurrentProcess (), p->to_master,
2627 client, &repl.to_master,
2628 0, TRUE, DUPLICATE_SAME_ACCESS))
2630 termios_printf ("DuplicateHandle (to_master), %E");
2631 goto reply;
2633 if (!DuplicateHandle (GetCurrentProcess (), p->to_slave_nat,
2634 client, &repl.to_slave_nat,
2635 0, TRUE, DUPLICATE_SAME_ACCESS))
2637 termios_printf ("DuplicateHandle (to_slave_nat), %E");
2638 goto reply;
2640 if (!DuplicateHandle (GetCurrentProcess (), p->to_slave,
2641 client, &repl.to_slave,
2642 0, TRUE, DUPLICATE_SAME_ACCESS))
2644 termios_printf ("DuplicateHandle (to_slave), %E");
2645 goto reply;
2648 reply:
2649 repl.error = GetLastError ();
2650 if (client)
2651 CloseHandle (client);
2652 if (deimp)
2653 cygheap->user.reimpersonate ();
2654 sd.free ();
2655 termios_printf ("Reply: from %p, to %p, error %u",
2656 repl.from_master_nat, repl.to_master_nat, repl.error );
2657 if (!WriteFile (p->master_ctl, &repl, sizeof repl, &len, NULL))
2658 termios_printf ("WriteFile, %E");
2659 if (!DisconnectNamedPipe (p->master_ctl))
2660 termios_printf ("DisconnectNamedPipe, %E");
2662 termios_printf ("Leaving");
2663 return 0;
2666 static DWORD
2667 pty_master_thread (VOID *arg)
2669 fhandler_pty_master::master_thread_param_t p;
2670 ((fhandler_pty_master *) arg)->get_master_thread_param (&p);
2671 return fhandler_pty_master::pty_master_thread (&p);
2674 /* The function pty_master_fwd_thread() should be static because the
2675 instance is deleted if the master is dup()'ed and the original is
2676 closed. In this case, dup()'ed instance still exists, therefore,
2677 master forwarding thread is also still alive even though the instance
2678 has been deleted. As a result, accesing member variables in this
2679 function causes access violation. */
2681 DWORD
2682 fhandler_pty_master::pty_master_fwd_thread (const master_fwd_thread_param_t *p)
2684 DWORD rlen;
2685 tmp_pathbuf tp;
2686 char *outbuf = tp.c_get ();
2687 char *mbbuf = tp.c_get ();
2688 static mbstate_t mbp;
2690 termios_printf ("Started.");
2691 for (;;)
2693 p->ttyp->fwd_last_time = GetTickCount64 ();
2694 DWORD n;
2695 p->ttyp->fwd_not_empty =
2696 ::bytes_available (n, p->from_slave_nat) && n;
2697 if (!ReadFile (p->from_slave_nat, outbuf, NT_MAX_PATH, &rlen, NULL))
2699 termios_printf ("ReadFile for forwarding failed, %E");
2700 break;
2702 if (p->ttyp->stop_fwd_thread)
2703 break;
2704 ssize_t wlen = rlen;
2705 char *ptr = outbuf;
2706 if (p->ttyp->pcon_activated)
2708 /* Avoid setting window title to "cygwin-console-helper.exe" */
2709 int state = 0;
2710 int start_at = 0;
2711 for (DWORD i=0; i<rlen; i++)
2712 if (outbuf[i] == '\033')
2714 start_at = i;
2715 state = 1;
2716 continue;
2718 else if ((state == 1 && outbuf[i] == ']') ||
2719 (state == 2 && outbuf[i] == '0') ||
2720 (state == 3 && outbuf[i] == ';'))
2722 state ++;
2723 continue;
2725 else if (state == 4 && outbuf[i] == '\a')
2727 const char *helper_str = "\\bin\\cygwin-console-helper.exe";
2728 if (memmem (&outbuf[start_at], i + 1 - start_at,
2729 helper_str, strlen (helper_str)))
2731 memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
2732 rlen = wlen = start_at + rlen - i - 1;
2734 state = 0;
2735 continue;
2737 else if (outbuf[i] == '\a')
2739 state = 0;
2740 continue;
2743 /* Remove CSI > Pm m */
2744 state = 0;
2745 start_at = 0;
2746 for (DWORD i = 0; i < rlen; i++)
2747 if (outbuf[i] == '\033')
2749 start_at = i;
2750 state = 1;
2751 continue;
2753 else if ((state == 1 && outbuf[i] == '[')
2754 || (state == 2 && outbuf[i] == '>'))
2756 state ++;
2757 continue;
2759 else if (state == 3 && (isdigit (outbuf[i]) || outbuf[i] == ';'))
2760 continue;
2761 else if (state == 3 && outbuf[i] == 'm')
2763 memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
2764 rlen = wlen = start_at + rlen - i - 1;
2765 state = 0;
2766 i = start_at - 1;
2767 continue;
2769 else
2770 state = 0;
2772 /* Remove OSC Ps ; ? BEL/ST */
2773 for (DWORD i = 0; i < rlen; i++)
2774 if (state == 0 && outbuf[i] == '\033')
2776 start_at = i;
2777 state = 1;
2778 continue;
2780 else if ((state == 1 && outbuf[i] == ']')
2781 || (state == 2 && outbuf[i] == ';')
2782 || (state == 3 && outbuf[i] == '?')
2783 || (state == 4 && outbuf[i] == '\033'))
2785 state ++;
2786 continue;
2788 else if (state == 2 && isdigit (outbuf[i]))
2789 continue;
2790 else if ((state == 4 && outbuf[i] == '\a')
2791 || (state == 5 && outbuf[i] == '\\'))
2793 memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
2794 rlen = wlen = start_at + rlen - i - 1;
2795 state = 0;
2796 i = start_at - 1;
2797 continue;
2799 else
2800 state = 0;
2802 if (p->ttyp->term_code_page != CP_UTF8)
2804 size_t nlen = NT_MAX_PATH;
2805 convert_mb_str (p->ttyp->term_code_page, mbbuf, &nlen,
2806 CP_UTF8, ptr, wlen, &mbp);
2808 ptr = mbbuf;
2809 wlen = rlen = nlen;
2812 /* OPOST processing was already done in pseudo console,
2813 so just write it to to_master. */
2814 DWORD written;
2815 while (rlen>0)
2817 if (!WriteFile (p->to_master, ptr, wlen, &written, NULL))
2819 termios_printf ("WriteFile for forwarding failed, %E");
2820 break;
2822 ptr += written;
2823 wlen = (rlen -= written);
2825 continue;
2828 UINT cp_from;
2829 pinfo pinfo_target = pinfo (p->ttyp->invisible_console_pid);
2830 DWORD target_pid = 0;
2831 if (pinfo_target)
2832 target_pid = pinfo_target->dwProcessId;
2833 if (target_pid)
2835 /* Slave attaches to a different console than master.
2836 Therefore reattach here. */
2837 DWORD resume_pid =
2838 attach_console_temporarily (target_pid);
2839 cp_from = GetConsoleOutputCP ();
2840 resume_from_temporarily_attach (resume_pid);
2842 else
2843 cp_from = GetConsoleOutputCP ();
2845 if (p->ttyp->term_code_page != cp_from)
2847 size_t nlen = NT_MAX_PATH;
2848 convert_mb_str (p->ttyp->term_code_page, mbbuf, &nlen,
2849 cp_from, ptr, wlen, &mbp);
2851 ptr = mbbuf;
2852 wlen = rlen = nlen;
2855 WaitForSingleObject (p->output_mutex, mutex_timeout);
2856 while (rlen>0)
2858 if (!process_opost_output (p->to_master, ptr, wlen,
2859 true /* disable output_stopped */,
2860 p->ttyp, false))
2862 termios_printf ("WriteFile for forwarding failed, %E");
2863 break;
2865 ptr += wlen;
2866 wlen = (rlen -= wlen);
2868 ReleaseMutex (p->output_mutex);
2870 return 0;
2873 static DWORD
2874 pty_master_fwd_thread (VOID *arg)
2876 fhandler_pty_master::master_fwd_thread_param_t p;
2877 ((fhandler_pty_master *) arg)->get_master_fwd_thread_param (&p);
2878 return fhandler_pty_master::pty_master_fwd_thread (&p);
2881 inline static bool
2882 is_running_as_service (void)
2884 return check_token_membership (well_known_service_sid)
2885 || cygheap->user.saved_sid () == well_known_system_sid;
2888 bool
2889 fhandler_pty_master::setup ()
2891 int res;
2892 security_descriptor sd;
2893 SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE };
2895 /* Find an unallocated pty to use. */
2896 /* Create a pipe for cygwin app (master to slave) simultaneously. */
2897 int unit = cygwin_shared->tty.allocate (from_master, get_output_handle ());
2898 if (unit < 0)
2899 return false;
2901 ProtectHandle1 (get_output_handle (), to_pty);
2903 tty& t = *cygwin_shared->tty[unit];
2904 _tc = (tty_min *) &t;
2906 tcinit (true); /* Set termios information. Force initialization. */
2908 const char *errstr = NULL;
2909 DWORD pipe_mode = PIPE_NOWAIT;
2911 if (!SetNamedPipeHandleState (get_output_handle (), &pipe_mode, NULL, NULL))
2912 termios_printf ("can't set output_handle(%p) to non-blocking mode",
2913 get_output_handle ());
2915 /* Pipe for non-cygwin apps (slave to master) */
2916 char pipename[sizeof ("ptyNNNN-from-master-nat")];
2917 __small_sprintf (pipename, "pty%d-to-master-nat", unit);
2918 res = fhandler_pipe::create (&sec_none, &from_slave_nat, &to_master_nat,
2919 fhandler_pty_common::pipesize, pipename, 0);
2920 if (res)
2922 errstr = "output pipe for non-cygwin apps";
2923 goto err;
2926 /* Pipe for cygwin apps (slave to master) */
2927 __small_sprintf (pipename, "pty%d-to-master", unit);
2928 res = fhandler_pipe::create (&sec_none, &get_handle (), &to_master,
2929 fhandler_pty_common::pipesize, pipename, 0);
2930 if (res)
2932 errstr = "output pipe";
2933 goto err;
2936 /* Pipe for non-cygwin apps (master to slave) */
2937 __small_sprintf (pipename, "pty%d-from-master-nat", unit);
2938 /* FILE_FLAG_OVERLAPPED is specified here in order to prevent
2939 PeekNamedPipe() from blocking in transfer_input().
2940 Accordig to the official document, in order to access the handle
2941 opened with FILE_FLAG_OVERLAPPED, it is mandatory to pass the
2942 OVERLAPP structure, but in fact, it seems that the access will
2943 fallback to the blocking access if it is not specified. */
2944 res = fhandler_pipe::create (&sec_none, &from_master_nat, &to_slave_nat,
2945 fhandler_pty_common::pipesize, pipename,
2946 FILE_FLAG_OVERLAPPED);
2947 if (res)
2949 errstr = "input pipe";
2950 goto err;
2953 ProtectHandle1 (get_handle (), from_pty);
2955 __small_sprintf (pipename, "pty%d-echoloop", unit);
2956 res = fhandler_pipe::create (&sec_none, &echo_r, &echo_w,
2957 fhandler_pty_common::pipesize, pipename, 0);
2958 if (res)
2960 errstr = "echo pipe";
2961 goto err;
2964 /* Create security attribute. Default permissions are 0620. */
2965 sd.malloc (sizeof (SECURITY_DESCRIPTOR));
2966 RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
2967 if (!create_object_sd_from_attribute (myself->uid, myself->gid,
2968 S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP,
2969 sd))
2970 sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) sd;
2972 /* Carefully check that the input_available_event didn't already exist.
2973 This is a measure to make sure that the event security descriptor
2974 isn't occupied by a malicious process. We must make sure that the
2975 event's security descriptor is what we expect it to be. */
2976 if (!(input_available_event = t.get_event (errstr = INPUT_AVAILABLE_EVENT,
2977 &sa, TRUE))
2978 || GetLastError () == ERROR_ALREADY_EXISTS)
2979 goto err;
2981 char buf[MAX_PATH];
2982 errstr = shared_name (buf, OUTPUT_MUTEX, unit);
2983 if (!(output_mutex = CreateMutex (&sa, FALSE, buf)))
2984 goto err;
2986 errstr = shared_name (buf, INPUT_MUTEX, unit);
2987 if (!(input_mutex = CreateMutex (&sa, FALSE, buf)))
2988 goto err;
2990 errstr = shared_name (buf, PIPE_SW_MUTEX, unit);
2991 if (!(pipe_sw_mutex = CreateMutex (&sa, FALSE, buf)))
2992 goto err;
2994 if (!attach_mutex)
2995 attach_mutex = CreateMutex (&sec_none_nih, FALSE, NULL);
2997 /* Create master control pipe which allows the master to duplicate
2998 the pty pipe handles to processes which deserve it. */
2999 __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
3000 &cygheap->installation_key, unit);
3001 master_ctl = CreateNamedPipe (buf, PIPE_ACCESS_DUPLEX
3002 | FILE_FLAG_FIRST_PIPE_INSTANCE,
3003 PIPE_WAIT | PIPE_TYPE_MESSAGE
3004 | PIPE_READMODE_MESSAGE
3005 | PIPE_REJECT_REMOTE_CLIENTS,
3006 1, 4096, 4096, 0, &sec_all_nih);
3007 if (master_ctl == INVALID_HANDLE_VALUE)
3009 errstr = "pty master control pipe";
3010 goto err;
3013 thread_param_copied_event = CreateEvent(NULL, FALSE, FALSE, NULL);
3014 master_thread = new cygthread (::pty_master_thread, this, "ptym");
3015 if (!master_thread)
3017 errstr = "pty master control thread";
3018 goto err;
3020 WaitForSingleObject (thread_param_copied_event, INFINITE);
3022 master_fwd_thread = new cygthread (::pty_master_fwd_thread, this, "ptymf");
3023 if (!master_fwd_thread)
3025 errstr = "pty master forwarding thread";
3026 goto err;
3028 WaitForSingleObject (thread_param_copied_event, INFINITE);
3029 CloseHandle (thread_param_copied_event);
3031 t.set_from_master_nat (from_master_nat);
3032 t.set_from_master (from_master);
3033 t.set_to_master_nat (to_master_nat);
3034 t.set_to_master (to_master);
3035 t.set_to_slave_nat (to_slave_nat);
3036 t.set_to_slave (get_output_handle ());
3037 t.winsize.ws_col = 80;
3038 t.winsize.ws_row = 25;
3039 t.master_pid = myself->pid;
3041 dev ().parse (DEV_PTYM_MAJOR, unit);
3043 t.master_is_running_as_service = is_running_as_service ();
3045 termios_printf ("this %p, pty%d opened - from_pty <%p,%p>, to_pty %p",
3046 this, unit, from_slave_nat, get_handle (),
3047 get_output_handle ());
3048 return true;
3050 err:
3051 __seterrno ();
3052 close_maybe (from_slave_nat);
3053 close_maybe (to_slave_nat);
3054 close_maybe (get_handle ());
3055 close_maybe (get_output_handle ());
3056 close_maybe (input_available_event);
3057 close_maybe (output_mutex);
3058 close_maybe (input_mutex);
3059 close_maybe (from_master_nat);
3060 close_maybe (to_master_nat);
3061 close_maybe (to_master);
3062 close_maybe (echo_r);
3063 close_maybe (echo_w);
3064 close_maybe (master_ctl);
3065 /* The from_master must be closed last so that the same pty is not
3066 allocated before cleaning up the other corresponding instances. */
3067 close_maybe (from_master);
3068 termios_printf ("pty%d open failed - failed to create %s", unit, errstr);
3069 return false;
3072 void
3073 fhandler_pty_master::fixup_after_fork (HANDLE parent)
3075 DWORD wpid = GetCurrentProcessId ();
3076 fhandler_pty_master *arch = (fhandler_pty_master *) archetype;
3077 if (arch->dwProcessId != wpid)
3079 tty& t = *get_ttyp ();
3080 if (myself->pid == t.master_pid)
3082 t.set_from_master_nat (arch->from_master_nat);
3083 t.set_from_master (arch->from_master);
3084 t.set_to_master_nat (arch->to_master_nat);
3085 t.set_to_master (arch->to_master);
3087 arch->dwProcessId = wpid;
3089 from_master_nat = arch->from_master_nat;
3090 from_master = arch->from_master;
3091 to_master_nat = arch->to_master_nat;
3092 to_master = arch->to_master;
3093 #if 0 /* Not sure if this is necessary. */
3094 from_slave_nat = arch->from_slave_nat;
3095 to_slave_nat = arch->to_slave_nat;
3096 #endif
3097 report_tty_counts (this, "inherited master", "");
3100 void
3101 fhandler_pty_master::fixup_after_exec ()
3103 if (!close_on_exec ())
3104 fixup_after_fork (spawn_info->parent);
3105 else
3106 from_master_nat = from_master = to_master_nat = to_master =
3107 from_slave_nat = to_slave_nat = NULL;
3110 BOOL
3111 fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr,
3112 ssize_t& len, bool is_echo,
3113 tty *ttyp, bool is_nonblocking)
3115 ssize_t towrite = len;
3116 BOOL res = TRUE;
3117 if (ttyp->ti.c_lflag & FLUSHO)
3118 return res; /* Discard write data */
3119 while (towrite)
3121 if (!is_echo)
3123 if (ttyp->output_stopped && is_nonblocking)
3125 if (towrite < len)
3126 break;
3127 else
3129 set_errno (EAGAIN);
3130 len = -1;
3131 return TRUE;
3134 while (ttyp->output_stopped)
3135 cygwait (10);
3138 if (!(ttyp->ti.c_oflag & OPOST)) // raw output mode
3140 DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
3141 res = WriteFile (h, ptr, n, &n, NULL);
3142 if (!res)
3143 break;
3144 ptr = (char *) ptr + n;
3145 towrite -= n;
3147 else // post-process output
3149 char outbuf[OUT_BUFFER_SIZE + 1];
3150 char *buf = (char *)ptr;
3151 DWORD n = 0;
3152 ssize_t rc = 0;
3153 while (n < OUT_BUFFER_SIZE && rc < towrite)
3155 switch (buf[rc])
3157 case '\r':
3158 if ((ttyp->ti.c_oflag & ONOCR)
3159 && ttyp->column == 0)
3161 rc++;
3162 continue;
3164 if (ttyp->ti.c_oflag & OCRNL)
3166 outbuf[n++] = '\n';
3167 rc++;
3169 else
3171 outbuf[n++] = buf[rc++];
3172 ttyp->column = 0;
3174 break;
3175 case '\n':
3176 if (ttyp->ti.c_oflag & ONLCR)
3178 outbuf[n++] = '\r';
3179 ttyp->column = 0;
3181 if (ttyp->ti.c_oflag & ONLRET)
3182 ttyp->column = 0;
3183 outbuf[n++] = buf[rc++];
3184 break;
3185 default:
3186 outbuf[n++] = buf[rc++];
3187 ttyp->column++;
3188 break;
3191 res = WriteFile (h, outbuf, n, &n, NULL);
3192 if (!res)
3193 break;
3194 ptr = (char *) ptr + rc;
3195 towrite -= rc;
3198 len -= towrite;
3199 return res;
3202 /* Pseudo console supprot is realized using a tricky technic.
3203 PTY need the pseudo console handles, however, they cannot
3204 be retrieved by normal procedure. Therefore, run a helper
3205 process in a pseudo console and get them from the helper.
3206 Slave process will attach to the pseudo console in the
3207 helper process using AttachConsole(). */
3208 bool
3209 fhandler_pty_slave::setup_pseudoconsole ()
3211 /* If the legacy console mode is enabled, pseudo console seems
3212 not to work as expected. To determine console mode, registry
3213 key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
3214 reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
3215 if (reg.error ())
3216 return false;
3217 if (reg.get_dword (L"ForceV2", 1) == 0)
3219 termios_printf ("Pseudo console is disabled "
3220 "because the legacy console mode is enabled.");
3221 return false;
3224 /* Set switch_to_nat_pipe regardless whether stdin is the pty or not
3225 so that the non-cygwin app can work when it opens CONIN$. */
3226 bool switch_to_nat_pipe_orig = get_ttyp ()->switch_to_nat_pipe;
3227 get_ttyp ()->switch_to_nat_pipe = true;
3229 HANDLE hpConIn, hpConOut;
3230 if (get_ttyp ()->pcon_activated)
3231 { /* The pseudo console is already activated. */
3232 if (GetStdHandle (STD_INPUT_HANDLE) == get_handle ())
3233 { /* Send CSI6n just for requesting transfer input. */
3234 DWORD n;
3235 WaitForSingleObject (input_mutex, mutex_timeout);
3236 get_ttyp ()->req_xfer_input = true; /* indicates that this "ESC[6n"
3237 is just for transfer input */
3238 get_ttyp ()->pcon_start = true;
3239 get_ttyp ()->pcon_start_pid = myself->pid;
3240 WriteFile (get_output_handle (), "\033[6n", 4, &n, NULL);
3241 ReleaseMutex (input_mutex);
3242 while (get_ttyp ()->pcon_start_pid)
3243 /* wait for completion of transfer_input() in master::write(). */
3244 Sleep (1);
3246 /* Attach to the pseudo console which already exits. */
3247 HANDLE pcon_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE,
3248 get_ttyp ()->nat_pipe_owner_pid);
3249 if (pcon_owner == NULL)
3250 return false;
3251 DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_in,
3252 GetCurrentProcess (), &hpConIn,
3253 0, TRUE, DUPLICATE_SAME_ACCESS);
3254 DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_out,
3255 GetCurrentProcess (), &hpConOut,
3256 0, TRUE, DUPLICATE_SAME_ACCESS);
3257 CloseHandle (pcon_owner);
3258 acquire_attach_mutex (mutex_timeout);
3259 FreeConsole ();
3260 AttachConsole (get_ttyp ()->nat_pipe_owner_pid);
3261 init_console_handler (false);
3262 release_attach_mutex ();
3263 goto skip_create;
3266 STARTUPINFOEXW si;
3267 PROCESS_INFORMATION pi;
3268 HANDLE hello, goodbye;
3269 HANDLE hr, hw;
3270 HPCON hpcon;
3273 { /* Create new pseudo console */
3274 COORD size = {
3275 (SHORT) get_ttyp ()->winsize.ws_col,
3276 (SHORT) get_ttyp ()->winsize.ws_row
3278 const DWORD inherit_cursor = 1;
3279 hpcon = NULL;
3280 SetLastError (ERROR_SUCCESS);
3281 HRESULT res = CreatePseudoConsole (size, get_handle_nat (),
3282 get_output_handle_nat (),
3283 inherit_cursor, &hpcon);
3284 if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
3286 if (res != S_OK)
3287 system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
3288 GetLastError (), res);
3289 goto fallback;
3292 SIZE_T bytesRequired;
3293 InitializeProcThreadAttributeList (NULL, 2, 0, &bytesRequired);
3294 ZeroMemory (&si, sizeof (si));
3295 si.StartupInfo.cb = sizeof (STARTUPINFOEXW);
3296 si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
3297 HeapAlloc (GetProcessHeap (), 0, bytesRequired);
3298 if (si.lpAttributeList == NULL)
3299 goto cleanup_pseudo_console;
3300 if (!InitializeProcThreadAttributeList (si.lpAttributeList,
3301 2, 0, &bytesRequired))
3302 goto cleanup_heap;
3303 if (!UpdateProcThreadAttribute (si.lpAttributeList,
3305 PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
3306 hpcon, sizeof (hpcon), NULL, NULL))
3308 goto cleanup_heap;
3310 hello = CreateEvent (&sec_none, true, false, NULL);
3311 goodbye = CreateEvent (&sec_none, true, false, NULL);
3312 CreatePipe (&hr, &hw, &sec_none, 0);
3314 HANDLE handles_to_inherit[] = {hello, goodbye, hw};
3315 if (!UpdateProcThreadAttribute (si.lpAttributeList,
3317 PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
3318 handles_to_inherit,
3319 sizeof (handles_to_inherit),
3320 NULL, NULL))
3321 goto cleanup_event_and_pipes;
3323 /* Execute helper process */
3324 WCHAR cmd[MAX_PATH];
3325 path_conv helper ("/bin/cygwin-console-helper.exe");
3326 size_t len = helper.get_wide_win32_path_len ();
3327 helper.get_wide_win32_path (cmd);
3328 __small_swprintf (cmd + len, L" %p %p %p", hello, goodbye, hw);
3329 si.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
3330 si.StartupInfo.hStdInput = NULL;
3331 si.StartupInfo.hStdOutput = NULL;
3332 si.StartupInfo.hStdError = NULL;
3334 get_ttyp ()->pcon_activated = true;
3335 get_ttyp ()->pcon_start = true;
3336 get_ttyp ()->pcon_start_pid = myself->pid;
3337 if (!CreateProcessW (NULL, cmd, &sec_none, &sec_none,
3338 TRUE, EXTENDED_STARTUPINFO_PRESENT,
3339 NULL, NULL, &si.StartupInfo, &pi))
3340 goto cleanup_event_and_pipes;
3342 for (;;)
3344 DWORD wait_result = WaitForSingleObject (hello, 500);
3345 if (wait_result == WAIT_OBJECT_0)
3346 break;
3347 if (wait_result != WAIT_TIMEOUT)
3348 goto cleanup_helper_with_hello;
3349 DWORD exit_code;
3350 if (!GetExitCodeProcess (pi.hProcess, &exit_code))
3351 goto cleanup_helper_with_hello;
3352 if (exit_code == STILL_ACTIVE)
3353 continue;
3354 if (exit_code != 0 ||
3355 WaitForSingleObject (hello, 500) != WAIT_OBJECT_0)
3356 goto cleanup_helper_with_hello;
3357 break;
3359 CloseHandle (hello);
3360 CloseHandle (pi.hThread);
3362 /* Duplicate pseudo console handles */
3363 DWORD rlen;
3364 char buf[64];
3365 if (!ReadFile (hr, buf, sizeof (buf), &rlen, NULL))
3366 goto cleanup_helper_process;
3367 buf[rlen] = '\0';
3368 sscanf (buf, "StdHandles=%p,%p", &hpConIn, &hpConOut);
3369 if (!DuplicateHandle (pi.hProcess, hpConIn,
3370 GetCurrentProcess (), &hpConIn, 0,
3371 TRUE, DUPLICATE_SAME_ACCESS))
3372 goto cleanup_helper_process;
3373 if (!DuplicateHandle (pi.hProcess, hpConOut,
3374 GetCurrentProcess (), &hpConOut, 0,
3375 TRUE, DUPLICATE_SAME_ACCESS))
3376 goto cleanup_pcon_in;
3378 CloseHandle (hr);
3379 CloseHandle (hw);
3380 DeleteProcThreadAttributeList (si.lpAttributeList);
3381 HeapFree (GetProcessHeap (), 0, si.lpAttributeList);
3383 /* Attach to pseudo console */
3384 acquire_attach_mutex (mutex_timeout);
3385 FreeConsole ();
3386 AttachConsole (pi.dwProcessId);
3387 init_console_handler (false);
3388 release_attach_mutex ();
3390 /* Terminate helper process */
3391 SetEvent (goodbye);
3392 WaitForSingleObject (pi.hProcess, INFINITE);
3393 CloseHandle (goodbye);
3394 CloseHandle (pi.hProcess);
3396 while (false);
3398 skip_create:
3401 /* Fixup handles */
3402 HANDLE orig_input_handle_nat = get_handle_nat ();
3403 HANDLE orig_output_handle_nat = get_output_handle_nat ();
3404 cygheap_fdenum cfd (false);
3405 while (cfd.next () >= 0)
3406 if (cfd->get_device () == get_device ())
3408 fhandler_base *fh = cfd;
3409 fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
3410 if (ptys->get_handle_nat () == orig_input_handle_nat)
3411 ptys->set_handle_nat (hpConIn);
3412 if (ptys->get_output_handle_nat () == orig_output_handle_nat)
3413 ptys->set_output_handle_nat (hpConOut);
3415 CloseHandle (orig_input_handle_nat);
3416 CloseHandle (orig_output_handle_nat);
3418 while (false);
3420 if (!process_alive (get_ttyp ()->nat_pipe_owner_pid))
3421 get_ttyp ()->nat_pipe_owner_pid = myself->exec_dwProcessId;
3423 if (hpcon && nat_pipe_owner_self (get_ttyp ()->nat_pipe_owner_pid))
3425 HPCON_INTERNAL *hp = (HPCON_INTERNAL *) hpcon;
3426 get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
3427 get_ttyp ()->h_pcon_condrv_reference = hp->hConDrvReference;
3428 get_ttyp ()->h_pcon_conhost_process = hp->hConHostProcess;
3429 DuplicateHandle (GetCurrentProcess (), hpConIn,
3430 GetCurrentProcess (), &get_ttyp ()->h_pcon_in,
3431 0, TRUE, DUPLICATE_SAME_ACCESS);
3432 DuplicateHandle (GetCurrentProcess (), hpConOut,
3433 GetCurrentProcess (), &get_ttyp ()->h_pcon_out,
3434 0, TRUE, DUPLICATE_SAME_ACCESS);
3435 /* Discard the pseudo console handler container here.
3436 Reconstruct it temporary when it is needed. */
3437 HeapFree (GetProcessHeap (), 0, hp);
3440 acquire_attach_mutex (mutex_timeout);
3441 if (get_ttyp ()->previous_code_page)
3442 SetConsoleCP (get_ttyp ()->previous_code_page);
3443 if (get_ttyp ()->previous_output_code_page)
3444 SetConsoleOutputCP (get_ttyp ()->previous_output_code_page);
3446 if (get_ttyp ()->getpgid () == myself->pgid)
3448 termios &t = get_ttyp ()->ti;
3449 DWORD mode;
3450 /* Set input mode */
3451 GetConsoleMode (hpConIn, &mode);
3452 mode &= ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
3453 if (t.c_lflag & ECHO)
3454 mode |= ENABLE_ECHO_INPUT;
3455 if (t.c_lflag & ICANON)
3456 mode |= ENABLE_LINE_INPUT;
3457 if (mode & ENABLE_ECHO_INPUT && !(mode & ENABLE_LINE_INPUT))
3458 /* This is illegal, so turn off the echo here, and fake it
3459 when we read the characters */
3460 mode &= ~ENABLE_ECHO_INPUT;
3461 if (t.c_lflag & ISIG)
3462 mode |= ENABLE_PROCESSED_INPUT;
3463 SetConsoleMode (hpConIn, mode);
3464 /* Set output mode */
3465 GetConsoleMode (hpConOut, &mode);
3466 mode &= ~DISABLE_NEWLINE_AUTO_RETURN;
3467 if (!(t.c_oflag & OPOST) || !(t.c_oflag & ONLCR))
3468 mode |= DISABLE_NEWLINE_AUTO_RETURN;
3469 SetConsoleMode (hpConOut, mode);
3471 release_attach_mutex ();
3473 return true;
3475 cleanup_helper_with_hello:
3476 CloseHandle (hello);
3477 CloseHandle (pi.hThread);
3478 goto cleanup_helper_process;
3479 cleanup_pcon_in:
3480 CloseHandle (hpConIn);
3481 cleanup_helper_process:
3482 SetEvent (goodbye);
3483 WaitForSingleObject (pi.hProcess, INFINITE);
3484 CloseHandle (pi.hProcess);
3485 goto skip_close_hello;
3486 cleanup_event_and_pipes:
3487 CloseHandle (hello);
3488 skip_close_hello:
3489 get_ttyp ()->pcon_start = false;
3490 get_ttyp ()->pcon_start_pid = 0;
3491 get_ttyp ()->pcon_activated = false;
3492 CloseHandle (goodbye);
3493 CloseHandle (hr);
3494 CloseHandle (hw);
3495 cleanup_heap:
3496 HeapFree (GetProcessHeap (), 0, si.lpAttributeList);
3497 cleanup_pseudo_console:
3498 if (hpcon)
3500 HPCON_INTERNAL *hp = (HPCON_INTERNAL *) hpcon;
3501 HANDLE tmp = hp->hConHostProcess;
3502 ClosePseudoConsole (hpcon);
3503 CloseHandle (tmp);
3505 fallback:
3506 get_ttyp ()->switch_to_nat_pipe = switch_to_nat_pipe_orig;
3507 return false;
3510 /* Find a process to which the ownership of nat pipe should be handed over */
3511 DWORD
3512 fhandler_pty_slave::get_winpid_to_hand_over (tty *ttyp,
3513 DWORD force_switch_to)
3515 DWORD switch_to = 0;
3516 if (force_switch_to)
3518 switch_to = force_switch_to;
3519 ttyp->setpgid (force_switch_to + MAX_PID);
3521 else if (nat_pipe_owner_self (ttyp->nat_pipe_owner_pid))
3523 /* Search another native process which attaches to the same console */
3524 DWORD current_pid = myself->exec_dwProcessId ?: myself->dwProcessId;
3525 switch_to = get_console_process_id (current_pid,
3526 false, true, true, true);
3527 if (!switch_to)
3528 switch_to = get_console_process_id (current_pid,
3529 false, true, false, true);
3531 return switch_to;
3534 void
3535 fhandler_pty_slave::hand_over_only (tty *ttyp, DWORD force_switch_to)
3537 if (nat_pipe_owner_self (ttyp->nat_pipe_owner_pid))
3539 DWORD switch_to = get_winpid_to_hand_over (ttyp, force_switch_to);
3540 if (switch_to)
3541 /* The process switch_to takes over the ownership of the nat pipe. */
3542 ttyp->nat_pipe_owner_pid = switch_to;
3543 else
3545 /* Abandon the ownership of the nat pipe */
3546 ttyp->nat_pipe_owner_pid = 0;
3547 ttyp->switch_to_nat_pipe = false;
3552 /* The function close_pseudoconsole() should be static so that it can
3553 be called even after the fhandler_pty_slave instance is deleted. */
3554 void
3555 fhandler_pty_slave::close_pseudoconsole (tty *ttyp, DWORD force_switch_to)
3557 DWORD switch_to = get_winpid_to_hand_over (ttyp, force_switch_to);
3558 acquire_attach_mutex (mutex_timeout);
3559 ttyp->previous_code_page = GetConsoleCP ();
3560 ttyp->previous_output_code_page = GetConsoleOutputCP ();
3561 release_attach_mutex ();
3562 if (nat_pipe_owner_self (ttyp->nat_pipe_owner_pid))
3563 { /* I am owner of the nat pipe. */
3564 if (switch_to)
3566 /* Change pseudo console owner to another process (switch_to). */
3567 HANDLE new_owner =
3568 OpenProcess (PROCESS_DUP_HANDLE, FALSE, switch_to);
3569 HANDLE new_write_pipe = NULL;
3570 HANDLE new_condrv_reference = NULL;
3571 HANDLE new_conhost_process = NULL;
3572 HANDLE new_pcon_in = NULL, new_pcon_out = NULL;
3573 DuplicateHandle (GetCurrentProcess (),
3574 ttyp->h_pcon_write_pipe,
3575 new_owner, &new_write_pipe,
3576 0, FALSE, DUPLICATE_SAME_ACCESS);
3577 DuplicateHandle (GetCurrentProcess (),
3578 ttyp->h_pcon_condrv_reference,
3579 new_owner, &new_condrv_reference,
3580 0, FALSE, DUPLICATE_SAME_ACCESS);
3581 DuplicateHandle (GetCurrentProcess (),
3582 ttyp->h_pcon_conhost_process,
3583 new_owner, &new_conhost_process,
3584 0, FALSE, DUPLICATE_SAME_ACCESS);
3585 DuplicateHandle (GetCurrentProcess (), ttyp->h_pcon_in,
3586 new_owner, &new_pcon_in,
3587 0, TRUE, DUPLICATE_SAME_ACCESS);
3588 DuplicateHandle (GetCurrentProcess (), ttyp->h_pcon_out,
3589 new_owner, &new_pcon_out,
3590 0, TRUE, DUPLICATE_SAME_ACCESS);
3591 CloseHandle (new_owner);
3592 CloseHandle (ttyp->h_pcon_write_pipe);
3593 CloseHandle (ttyp->h_pcon_condrv_reference);
3594 CloseHandle (ttyp->h_pcon_conhost_process);
3595 CloseHandle (ttyp->h_pcon_in);
3596 CloseHandle (ttyp->h_pcon_out);
3597 ttyp->nat_pipe_owner_pid = switch_to;
3598 ttyp->h_pcon_write_pipe = new_write_pipe;
3599 ttyp->h_pcon_condrv_reference = new_condrv_reference;
3600 ttyp->h_pcon_conhost_process = new_conhost_process;
3601 ttyp->h_pcon_in = new_pcon_in;
3602 ttyp->h_pcon_out = new_pcon_out;
3603 acquire_attach_mutex (mutex_timeout);
3604 FreeConsole ();
3605 pinfo p (myself->ppid);
3606 if (!p || !AttachConsole (p->dwProcessId))
3607 AttachConsole (ATTACH_PARENT_PROCESS);
3608 init_console_handler (false);
3609 release_attach_mutex ();
3611 else
3612 { /* Close pseudo console and abandon the ownership of the nat pipe. */
3613 acquire_attach_mutex (mutex_timeout);
3614 FreeConsole ();
3615 pinfo p (myself->ppid);
3616 if (!p || !AttachConsole (p->dwProcessId))
3617 AttachConsole (ATTACH_PARENT_PROCESS);
3618 init_console_handler (false);
3619 release_attach_mutex ();
3620 /* Reconstruct pseudo console handler container here for close */
3621 HPCON_INTERNAL *hp =
3622 (HPCON_INTERNAL *) HeapAlloc (GetProcessHeap (), 0,
3623 sizeof (HPCON_INTERNAL));
3624 hp->hWritePipe = ttyp->h_pcon_write_pipe;
3625 hp->hConDrvReference = ttyp->h_pcon_condrv_reference;
3626 hp->hConHostProcess = ttyp->h_pcon_conhost_process;
3627 /* HeapFree() will be called in ClosePseudoConsole() */
3628 ClosePseudoConsole ((HPCON) hp);
3629 CloseHandle (ttyp->h_pcon_conhost_process);
3630 ttyp->pcon_activated = false;
3631 ttyp->switch_to_nat_pipe = false;
3632 ttyp->nat_pipe_owner_pid = 0;
3633 ttyp->pcon_start = false;
3634 ttyp->pcon_start_pid = 0;
3637 else
3638 { /* Just detach from the pseudo console if I am not owner. */
3639 acquire_attach_mutex (mutex_timeout);
3640 FreeConsole ();
3641 pinfo p (myself->ppid);
3642 if (!p || !AttachConsole (p->dwProcessId))
3643 AttachConsole (ATTACH_PARENT_PROCESS);
3644 init_console_handler (false);
3645 release_attach_mutex ();
3649 static bool
3650 has_ansi_escape_sequences (const WCHAR *env)
3652 /* Retrieve TERM name */
3653 const char *term = NULL;
3654 char term_str[260];
3655 if (env)
3657 for (const WCHAR *p = env; *p != L'\0'; p += wcslen (p) + 1)
3658 if (swscanf (p, L"TERM=%236s", term_str) == 1)
3660 term = term_str;
3661 break;
3664 else
3665 term = getenv ("TERM");
3667 if (!term)
3668 return false;
3670 /* If cursor_home is not "\033[H", terminal is not supposed to
3671 support ANSI escape sequences. */
3672 char tinfo[260];
3673 __small_sprintf (tinfo, "/usr/share/terminfo/%02x/%s", term[0], term);
3674 path_conv path (tinfo);
3675 WCHAR wtinfo[260];
3676 path.get_wide_win32_path (wtinfo);
3677 HANDLE h;
3678 h = CreateFileW (wtinfo, GENERIC_READ, FILE_SHARE_READ,
3679 NULL, OPEN_EXISTING, 0, NULL);
3680 if (h == NULL)
3681 return false;
3682 char terminfo[4096];
3683 DWORD n;
3684 ReadFile (h, terminfo, sizeof (terminfo), &n, 0);
3685 CloseHandle (h);
3687 int num_size = 2;
3688 if (*(int16_t *)terminfo == 01036 /* MAGIC2 */)
3689 num_size = 4;
3690 const int name_pos = 12; /* Position of terminal name */
3691 const int name_size = *(int16_t *) (terminfo + 2);
3692 const int bool_count = *(int16_t *) (terminfo + 4);
3693 const int num_count = *(int16_t *) (terminfo + 6);
3694 const int str_count = *(int16_t *) (terminfo + 8);
3695 const int str_size = *(int16_t *) (terminfo + 10);
3696 const int cursor_home = 12; /* cursor_home entry index */
3697 if (cursor_home >= str_count)
3698 return false;
3699 int str_idx_pos = name_pos + name_size + bool_count + num_size * num_count;
3700 if (str_idx_pos & 1)
3701 str_idx_pos ++;
3702 const int16_t *str_idx = (int16_t *) (terminfo + str_idx_pos);
3703 const char *str_table = (const char *) (str_idx + str_count);
3704 if (str_idx + cursor_home >= (int16_t *) (terminfo + n))
3705 return false;
3706 if (str_idx[cursor_home] == -1)
3707 return false;
3708 const char *cursor_home_str = str_table + str_idx[cursor_home];
3709 if (cursor_home_str >= str_table + str_size)
3710 return false;
3711 if (cursor_home_str >= terminfo + n)
3712 return false;
3713 if (strcmp (cursor_home_str, "\033[H") != 0)
3714 return false;
3715 return true;
3718 bool
3719 fhandler_pty_slave::term_has_pcon_cap (const WCHAR *env)
3721 if (get_ttyp ()->pcon_cap_checked)
3722 return get_ttyp ()->has_csi6n;
3724 DWORD n;
3725 char buf[1024];
3726 char *p;
3727 int len;
3728 int wait_cnt = 0;
3730 /* Check if terminal has ANSI escape sequence. */
3731 if (!has_ansi_escape_sequences (env))
3732 goto maybe_dumb;
3734 /* Check if terminal has CSI6n */
3735 WaitForSingleObject (pipe_sw_mutex, INFINITE);
3736 WaitForSingleObject (input_mutex, mutex_timeout);
3737 /* Set pcon_activated and pcon_start so that the response
3738 will sent to io_handle_nat rather than io_handle. */
3739 get_ttyp ()->pcon_activated = true;
3740 /* pcon_start will be cleared in master write() when CSI6n is responded. */
3741 get_ttyp ()->pcon_start = true;
3742 WriteFile (get_output_handle (), "\033[6n", 4, &n, NULL);
3743 ReleaseMutex (input_mutex);
3744 p = buf;
3745 len = sizeof (buf) - 1;
3748 if (::bytes_available (n, get_handle_nat ()) && n)
3750 ReadFile (get_handle_nat (), p, len, &n, NULL);
3751 p += n;
3752 len -= n;
3753 *p = '\0';
3754 char *p1 = strrchr (buf, '\033');
3755 int x, y;
3756 char c;
3757 if (p1 == NULL || sscanf (p1, "\033[%d;%d%c", &y, &x, &c) != 3
3758 || c != 'R')
3759 continue;
3760 wait_cnt = 0;
3761 break;
3763 else if (++wait_cnt > 100) /* Timeout */
3764 goto not_has_csi6n;
3765 else
3766 Sleep (1);
3768 while (len);
3769 get_ttyp ()->pcon_activated = false;
3770 get_ttyp ()->nat_pipe_owner_pid = 0;
3771 ReleaseMutex (pipe_sw_mutex);
3772 if (len == 0)
3773 goto not_has_csi6n;
3775 get_ttyp ()->has_csi6n = true;
3776 get_ttyp ()->pcon_cap_checked = true;
3778 return true;
3780 not_has_csi6n:
3781 WaitForSingleObject (input_mutex, mutex_timeout);
3782 /* If CSI6n is not responded, pcon_start is not cleared
3783 in master write(). Therefore, clear it here manually. */
3784 get_ttyp ()->pcon_start = false;
3785 get_ttyp ()->pcon_activated = false;
3786 ReleaseMutex (input_mutex);
3787 ReleaseMutex (pipe_sw_mutex);
3788 maybe_dumb:
3789 get_ttyp ()->pcon_cap_checked = true;
3790 return false;
3793 void
3794 fhandler_pty_slave::create_invisible_console ()
3796 if (get_ttyp ()->need_invisible_console)
3798 /* Detach from console device and create new invisible console. */
3799 acquire_attach_mutex (mutex_timeout);
3800 FreeConsole();
3801 fhandler_console::need_invisible (true);
3802 init_console_handler (false);
3803 release_attach_mutex ();
3804 get_ttyp ()->need_invisible_console = false;
3805 get_ttyp ()->invisible_console_pid = myself->pid;
3807 if (get_ttyp ()->invisible_console_pid
3808 && !pinfo (get_ttyp ()->invisible_console_pid))
3809 /* If primary slave process does not exist anymore,
3810 this process becomes the primary. */
3811 get_ttyp ()->invisible_console_pid = myself->pid;
3814 void
3815 fhandler_pty_master::get_master_thread_param (master_thread_param_t *p)
3817 p->from_master_nat = from_master_nat;
3818 p->from_master = from_master;
3819 p->to_master_nat = to_master_nat;
3820 p->to_master = to_master;
3821 p->to_slave_nat = to_slave_nat;
3822 p->to_slave = get_output_handle ();
3823 p->master_ctl = master_ctl;
3824 p->input_available_event = input_available_event;
3825 SetEvent (thread_param_copied_event);
3828 void
3829 fhandler_pty_master::get_master_fwd_thread_param (master_fwd_thread_param_t *p)
3831 p->to_master = to_master;
3832 p->from_slave_nat = from_slave_nat;
3833 p->output_mutex = output_mutex;
3834 p->ttyp = get_ttyp ();
3835 SetEvent (thread_param_copied_event);
3838 #define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
3839 #define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
3840 void
3841 fhandler_pty_slave::transfer_input (tty::xfer_dir dir, HANDLE from, tty *ttyp,
3842 HANDLE input_available_event)
3844 HANDLE to;
3845 if (dir == tty::to_nat)
3846 to = ttyp->to_slave_nat ();
3847 else
3848 to = ttyp->to_slave ();
3850 pinfo p (ttyp->master_pid);
3851 HANDLE pty_owner = NULL;
3852 if (p)
3853 pty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId);
3854 if (pty_owner)
3856 DuplicateHandle (pty_owner, to, GetCurrentProcess (), &to,
3857 0, TRUE, DUPLICATE_SAME_ACCESS);
3858 CloseHandle (pty_owner);
3860 else
3862 char pipe[MAX_PATH];
3863 __small_sprintf (pipe,
3864 "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
3865 &cygheap->installation_key, ttyp->get_minor ());
3866 pipe_request req = { GetCurrentProcessId () };
3867 pipe_reply repl;
3868 DWORD len;
3869 if (!CallNamedPipe (pipe, &req, sizeof req,
3870 &repl, sizeof repl, &len, 500))
3871 return; /* What can we do? */
3872 CloseHandle (repl.from_master_nat); /* not used. */
3873 CloseHandle (repl.from_master); /* not used. */
3874 CloseHandle (repl.to_master_nat); /* not used. */
3875 CloseHandle (repl.to_master); /* not used. */
3876 if (dir == tty::to_nat)
3878 CloseHandle (repl.to_slave); /* not used. */
3879 to = repl.to_slave_nat;
3881 else
3883 CloseHandle (repl.to_slave_nat); /* not used. */
3884 to = repl.to_slave;
3888 UINT cp_from = 0, cp_to = 0;
3890 if (dir == tty::to_nat)
3892 cp_from = ttyp->term_code_page;
3893 if (ttyp->pcon_activated)
3894 cp_to = CP_UTF8;
3895 else
3896 cp_to = GetConsoleCP ();
3898 else
3900 cp_from = GetConsoleCP ();
3901 cp_to = ttyp->term_code_page;
3904 tmp_pathbuf tp;
3905 char *buf = tp.c_get ();
3907 bool transfered = false;
3909 if (dir == tty::to_cyg && ttyp->pcon_activated)
3910 { /* from handle is console handle */
3911 /* Reaches here for nat->cyg case with pcon activated. */
3912 INPUT_RECORD r[INREC_SIZE];
3913 DWORD n;
3914 while (PeekConsoleInputA (from, r, INREC_SIZE, &n) && n)
3916 ReadConsoleInputA (from, r, n, &n);
3917 if (ttyp->discard_input)
3918 continue;
3919 int len = 0;
3920 char *ptr = buf;
3921 for (DWORD i = 0; i < n; i++)
3922 if (r[i].EventType == KEY_EVENT && r[i].Event.KeyEvent.bKeyDown)
3924 DWORD ctrl_key_state = r[i].Event.KeyEvent.dwControlKeyState;
3925 if (r[i].Event.KeyEvent.uChar.AsciiChar)
3927 if ((ctrl_key_state & ALT_PRESSED)
3928 && r[i].Event.KeyEvent.uChar.AsciiChar <= 0x7f)
3929 buf[len++] = '\033'; /* Meta */
3930 buf[len++] = r[i].Event.KeyEvent.uChar.AsciiChar;
3932 /* Allow Ctrl-Space to emit ^@ */
3933 else if (r[i].Event.KeyEvent.wVirtualKeyCode == '2'
3934 && (ctrl_key_state & CTRL_PRESSED)
3935 && !(ctrl_key_state & ALT_PRESSED))
3936 buf[len++] = '\0';
3937 else
3938 { /* arrow/function keys */
3939 /* FIXME: The current code generates cygwin terminal
3940 sequence rather than xterm sequence. */
3941 char tmp[16];
3942 const char *add =
3943 fhandler_console::get_nonascii_key (r[i], tmp);
3944 if (add)
3946 strcpy (buf + len, add);
3947 len += strlen (add);
3951 if (cp_to != cp_from)
3953 static mbstate_t mbp;
3954 char *mbbuf = tp.c_get ();
3955 size_t nlen = NT_MAX_PATH;
3956 convert_mb_str (cp_to, mbbuf, &nlen, cp_from, buf, len, &mbp);
3957 ptr = mbbuf;
3958 len = nlen;
3960 /* Call WriteFile() line by line */
3961 char *p0 = ptr;
3962 char *p_cr = (char *) memchr (p0, '\r', len - (p0 - ptr));
3963 char *p_lf = (char *) memchr (p0, '\n', len - (p0 - ptr));
3964 while (p_cr || p_lf)
3966 char *p1 =
3967 p_cr ? (p_lf ? ((p_cr + 1 == p_lf)
3968 ? p_lf : min(p_cr, p_lf)) : p_cr) : p_lf;
3969 *p1 = '\n';
3970 n = p1 - p0 + 1;
3971 if (n && WriteFile (to, p0, n, &n, NULL) && n)
3972 transfered = true;
3973 p0 = p1 + 1;
3974 p_cr = (char *) memchr (p0, '\r', len - (p0 - ptr));
3975 p_lf = (char *) memchr (p0, '\n', len - (p0 - ptr));
3977 n = len - (p0 - ptr);
3978 if (n && WriteFile (to, p0, n, &n, NULL) && n)
3979 transfered = true;
3982 else
3983 { /* Reaches here when both cyg->nat and nat->cyg cases with
3984 pcon not activated or cyg->nat case with pcon activated. */
3985 DWORD bytes_in_pipe;
3986 while (::bytes_available (bytes_in_pipe, from) && bytes_in_pipe)
3988 DWORD n = MIN (bytes_in_pipe, NT_MAX_PATH);
3989 ReadFile (from, buf, n, &n, NULL);
3990 if (ttyp->discard_input)
3991 continue;
3992 char *ptr = buf;
3993 if (dir == tty::to_nat)
3995 char *p = buf;
3996 if (ttyp->pcon_activated)
3997 while ((p = (char *) memchr (p, '\n', n - (p - buf))))
3998 *p = '\r';
3999 else
4000 while ((p = (char *) memchr (p, '\r', n - (p - buf))))
4001 *p = '\n';
4003 if (cp_to != cp_from)
4005 static mbstate_t mbp;
4006 char *mbbuf = tp.c_get ();
4007 size_t nlen = NT_MAX_PATH;
4008 convert_mb_str (cp_to, mbbuf, &nlen, cp_from, buf, n, &mbp);
4009 ptr = mbbuf;
4010 n = nlen;
4012 if (n && WriteFile (to, ptr, n, &n, NULL) && n)
4013 transfered = true;;
4016 CloseHandle (to);
4018 /* Fix input_available_event which indicates availability in cyg pipe. */
4019 if (dir == tty::to_nat) /* all data is transfered to nat pipe,
4020 so no data available in cyg pipe. */
4021 ResetEvent (input_available_event);
4022 else if (transfered) /* There is data transfered to cyg pipe. */
4023 SetEvent (input_available_event);
4024 ttyp->pty_input_state = dir;
4025 ttyp->discard_input = false;
4028 void
4029 fhandler_pty_slave::cleanup_before_exit ()
4031 if (myself->process_state & PID_NOTCYGWIN)
4032 get_ttyp ()->wait_fwd ();
4035 void
4036 fhandler_pty_slave::get_duplicated_handle_set (handle_set_t *p)
4038 DuplicateHandle (GetCurrentProcess (), get_handle_nat (),
4039 GetCurrentProcess (), &p->from_master_nat,
4040 0, 0, DUPLICATE_SAME_ACCESS);
4041 DuplicateHandle (GetCurrentProcess (), input_available_event,
4042 GetCurrentProcess (), &p->input_available_event,
4043 0, 0, DUPLICATE_SAME_ACCESS);
4044 DuplicateHandle (GetCurrentProcess (), input_mutex,
4045 GetCurrentProcess (), &p->input_mutex,
4046 0, 0, DUPLICATE_SAME_ACCESS);
4047 DuplicateHandle (GetCurrentProcess (), pipe_sw_mutex,
4048 GetCurrentProcess (), &p->pipe_sw_mutex,
4049 0, 0, DUPLICATE_SAME_ACCESS);
4052 void
4053 fhandler_pty_slave::close_handle_set (handle_set_t *p)
4055 CloseHandle (p->from_master_nat);
4056 p->from_master_nat = NULL;
4057 CloseHandle (p->input_available_event);
4058 p->input_available_event = NULL;
4059 CloseHandle (p->input_mutex);
4060 p->input_mutex = NULL;
4061 CloseHandle (p->pipe_sw_mutex);
4062 p->pipe_sw_mutex = NULL;
4065 void
4066 fhandler_pty_slave::setup_for_non_cygwin_app (bool nopcon,
4067 const WCHAR *envblock,
4068 bool stdin_is_ptys)
4070 if (disable_pcon || !term_has_pcon_cap (envblock))
4071 nopcon = true;
4072 WaitForSingleObject (pipe_sw_mutex, INFINITE);
4073 /* Setting switch_to_nat_pipe is necessary even if pseudo console
4074 will not be activated. */
4075 fhandler_base *fh = ::cygheap->fdtab[0];
4076 if (fh && fh->get_major () == DEV_PTYS_MAJOR)
4078 fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
4079 ptys->get_ttyp ()->switch_to_nat_pipe = true;
4080 if (!process_alive (ptys->get_ttyp ()->nat_pipe_owner_pid))
4081 ptys->get_ttyp ()->nat_pipe_owner_pid = myself->exec_dwProcessId;
4083 bool pcon_enabled = false;
4084 if (!nopcon)
4085 pcon_enabled = setup_pseudoconsole ();
4086 ReleaseMutex (pipe_sw_mutex);
4087 /* For pcon enabled case, transfer_input() is called in master::write() */
4088 if (!pcon_enabled && get_ttyp ()->getpgid () == myself->pgid
4089 && stdin_is_ptys && get_ttyp ()->pty_input_state_eq (tty::to_cyg))
4091 WaitForSingleObject (input_mutex, mutex_timeout);
4092 acquire_attach_mutex (mutex_timeout);
4093 transfer_input (tty::to_nat, get_handle (), get_ttyp (),
4094 input_available_event);
4095 release_attach_mutex ();
4096 ReleaseMutex (input_mutex);
4100 void
4101 fhandler_pty_slave::cleanup_for_non_cygwin_app (handle_set_t *p, tty *ttyp,
4102 bool stdin_is_ptys,
4103 DWORD force_switch_to)
4105 ttyp->wait_fwd ();
4106 WaitForSingleObject (p->pipe_sw_mutex, INFINITE);
4107 DWORD switch_to = get_winpid_to_hand_over (ttyp, force_switch_to);
4108 if ((!switch_to && (ttyp->pcon_activated || stdin_is_ptys))
4109 && ttyp->pty_input_state_eq (tty::to_nat))
4111 WaitForSingleObject (p->input_mutex, mutex_timeout);
4112 acquire_attach_mutex (mutex_timeout);
4113 transfer_input (tty::to_cyg, p->from_master_nat, ttyp,
4114 p->input_available_event);
4115 release_attach_mutex ();
4116 ReleaseMutex (p->input_mutex);
4118 if (ttyp->pcon_activated)
4119 close_pseudoconsole (ttyp, force_switch_to);
4120 else
4121 hand_over_only (ttyp, force_switch_to);
4122 ReleaseMutex (p->pipe_sw_mutex);
4125 void
4126 fhandler_pty_slave::setpgid_aux (pid_t pid)
4128 reset_switch_to_nat_pipe ();
4130 WaitForSingleObject (pipe_sw_mutex, INFINITE);
4131 bool was_nat_fg = get_ttyp ()->nat_fg (tc ()->pgid);
4132 bool nat_fg = get_ttyp ()->nat_fg (pid);
4133 if (!was_nat_fg && nat_fg && get_ttyp ()->switch_to_nat_pipe
4134 && get_ttyp ()->pty_input_state_eq (tty::to_cyg))
4136 WaitForSingleObject (input_mutex, mutex_timeout);
4137 acquire_attach_mutex (mutex_timeout);
4138 transfer_input (tty::to_nat, get_handle (), get_ttyp (),
4139 input_available_event);
4140 release_attach_mutex ();
4141 ReleaseMutex (input_mutex);
4143 else if (was_nat_fg && !nat_fg && get_ttyp ()->switch_to_nat_pipe
4144 && get_ttyp ()->pty_input_state_eq (tty::to_nat))
4146 bool attach_restore = false;
4147 HANDLE from = get_handle_nat ();
4148 DWORD resume_pid = 0;
4149 WaitForSingleObject (input_mutex, mutex_timeout);
4150 if (get_ttyp ()->pcon_activated && get_ttyp ()->nat_pipe_owner_pid
4151 && !get_console_process_id (get_ttyp ()->nat_pipe_owner_pid, true))
4153 HANDLE pcon_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE,
4154 get_ttyp ()->nat_pipe_owner_pid);
4155 DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_in,
4156 GetCurrentProcess (), &from,
4157 0, TRUE, DUPLICATE_SAME_ACCESS);
4158 CloseHandle (pcon_owner);
4159 DWORD target_pid = get_ttyp ()->nat_pipe_owner_pid;
4160 resume_pid = attach_console_temporarily (target_pid);
4161 attach_restore = true;
4163 else
4164 acquire_attach_mutex (mutex_timeout);
4165 transfer_input (tty::to_cyg, from, get_ttyp (), input_available_event);
4166 if (attach_restore)
4167 resume_from_temporarily_attach (resume_pid);
4168 else
4169 release_attach_mutex ();
4170 ReleaseMutex (input_mutex);
4172 ReleaseMutex (pipe_sw_mutex);
4175 bool
4176 fhandler_pty_master::need_send_ctrl_c_event ()
4178 /* If pseudo console is activated, sending CTRL_C_EVENT to non-cygwin
4179 apps will be done in pseudo console, therefore, sending it in
4180 fhandler_pty_master::write() duplicates that event for non-cygwin
4181 apps. So return false if pseudo console is activated. */
4182 return !(to_be_read_from_nat_pipe () && get_ttyp ()->pcon_activated
4183 && get_ttyp ()->pty_input_state == tty::to_nat);
4186 void
4187 fhandler_pty_slave::release_ownership_of_nat_pipe (tty *ttyp,
4188 fhandler_termios *fh)
4190 if (fh->get_major () == DEV_PTYM_MAJOR
4191 && nat_pipe_owner_self (ttyp->nat_pipe_owner_pid))
4193 fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
4194 WaitForSingleObject (ptym->pipe_sw_mutex, INFINITE);
4195 if (ttyp->pcon_activated)
4196 /* Do not acquire/release_attach_mutex() here because
4197 it has done in fhandler_termios::process_sigs(). */
4198 close_pseudoconsole (ttyp);
4199 else
4200 hand_over_only (ttyp);
4201 ReleaseMutex (ptym->pipe_sw_mutex);
4205 DWORD
4206 fhandler_pty_common::attach_console_temporarily (DWORD target_pid)
4208 DWORD resume_pid = 0;
4209 acquire_attach_mutex (mutex_timeout);
4210 pinfo pinfo_resume (myself->ppid);
4211 if (pinfo_resume)
4212 resume_pid = pinfo_resume->dwProcessId;
4213 if (!resume_pid)
4214 resume_pid = get_console_process_id (myself->dwProcessId, false);
4215 bool console_exists = fhandler_console::exists ();
4216 if (!console_exists || resume_pid)
4218 FreeConsole ();
4219 AttachConsole (target_pid);
4220 init_console_handler (false);
4222 return console_exists ? resume_pid : (DWORD) -1;
4225 void
4226 fhandler_pty_common::resume_from_temporarily_attach (DWORD resume_pid)
4228 bool console_exists = (resume_pid != (DWORD) -1);
4229 if (!console_exists || resume_pid)
4231 FreeConsole ();
4232 if (console_exists)
4233 if (!resume_pid || !AttachConsole (resume_pid))
4234 AttachConsole (ATTACH_PARENT_PROCESS);
4235 init_console_handler (false);
4237 release_attach_mutex ();