]> cygwin.com Git - newlib-cygwin.git/blob - winsup/cygwin/fhandler_tty.cc
Revert "Cygwin: fix permission problem when writing DAC info on Samba shares"
[newlib-cygwin.git] / winsup / cygwin / fhandler_tty.cc
1 /* fhandler_tty.cc
2
3 This file is part of Cygwin.
4
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. */
8
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"
31
32 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
33 #define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016
34 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
35
36 extern DWORD mutex_timeout; /* defined in fhandler_termios.cc */
37
38 extern "C" int sscanf (const char *, const char *, ...);
39
40 #define close_maybe(h) \
41 do { \
42 if (h && h != INVALID_HANDLE_VALUE) \
43 CloseHandle (h); \
44 } while (0)
45
46 /* pty master control pipe messages */
47 struct pipe_request {
48 DWORD pid;
49 };
50
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;
59 };
60
61 HANDLE attach_mutex;
62
63 DWORD acquire_attach_mutex (DWORD t)
64 {
65 if (!attach_mutex)
66 return WAIT_OBJECT_0;
67 return WaitForSingleObject (attach_mutex, t);
68 }
69
70 void release_attach_mutex (void)
71 {
72 if (!attach_mutex)
73 return;
74 ReleaseMutex (attach_mutex);
75 }
76
77 inline static bool pcon_pid_alive (DWORD pid);
78
79 DWORD
80 fhandler_pty_common::get_console_process_id (DWORD pid, bool match,
81 bool cygwin, bool stub_only)
82 {
83 tmp_pathbuf tp;
84 DWORD *list = (DWORD *) tp.c_get ();
85 const DWORD buf_size = NT_MAX_PATH / sizeof (DWORD);
86
87 DWORD num = GetConsoleProcessList (list, buf_size);
88 if (num == 0 || num > buf_size)
89 return 0;
90
91 DWORD res_pri = 0, res = 0;
92 /* Last one is the oldest. */
93 /* https://github.com/microsoft/terminal/issues/95 */
94 for (int i = (int) num - 1; i >= 0; i--)
95 if ((match && list[i] == pid) || (!match && list[i] != pid))
96 {
97 if (!cygwin)
98 {
99 res_pri = list[i];
100 break;
101 }
102 else
103 {
104 pinfo p (cygwin_pid (list[i]));
105 if (!!p && p->exec_dwProcessId)
106 {
107 res_pri = stub_only ? p->exec_dwProcessId : list[i];
108 break;
109 }
110 if (!p && !res && pcon_pid_alive (list[i]) && stub_only)
111 res = list[i];
112 if (!!p && !res && !stub_only)
113 res = list[i];
114 }
115 }
116 return res_pri ?: res;
117 }
118
119 static bool isHybrid;
120 static HANDLE h_gdb_process;
121
122 static void
123 set_switch_to_pcon (HANDLE *in, HANDLE *out, HANDLE *err, bool iscygwin)
124 {
125 cygheap_fdenum cfd (false);
126 int fd;
127 fhandler_base *replace_in = NULL, *replace_out = NULL, *replace_err = NULL;
128 fhandler_pty_slave *ptys_pcon = NULL;
129 while ((fd = cfd.next ()) >= 0)
130 {
131 if (*in == cfd->get_handle () ||
132 (fd == 0 && *in == GetStdHandle (STD_INPUT_HANDLE)))
133 replace_in = (fhandler_base *) cfd;
134 if (*out == cfd->get_output_handle () ||
135 (fd == 1 && *out == GetStdHandle (STD_OUTPUT_HANDLE)))
136 replace_out = (fhandler_base *) cfd;
137 if (*err == cfd->get_output_handle () ||
138 (fd == 2 && *err == GetStdHandle (STD_ERROR_HANDLE)))
139 replace_err = (fhandler_base *) cfd;
140 if (cfd->get_device () == (dev_t) myself->ctty)
141 {
142 fhandler_base *fh = cfd;
143 fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
144 if (*in == ptys->get_handle ()
145 || *out == ptys->get_output_handle ()
146 || *err == ptys->get_output_handle ())
147 ptys_pcon = ptys;
148 }
149 }
150 if (!iscygwin && ptys_pcon)
151 ptys_pcon->set_switch_to_pcon ();
152 if (replace_in)
153 *in = replace_in->get_handle_nat ();
154 if (replace_out)
155 *out = replace_out->get_output_handle_nat ();
156 if (replace_err)
157 *err = replace_err->get_output_handle_nat ();
158 }
159
160 static bool atexit_func_registered = false;
161 static bool debug_process = false;
162
163 static void
164 atexit_func (void)
165 {
166 if (isHybrid)
167 {
168 cygheap_fdenum cfd (false);
169 while (cfd.next () >= 0)
170 if (cfd->get_device () == (dev_t) myself->ctty)
171 {
172 DWORD force_switch_to = 0;
173 if (WaitForSingleObject (h_gdb_process, 0) == WAIT_TIMEOUT
174 && !debug_process)
175 force_switch_to = GetProcessId (h_gdb_process);
176 fhandler_base *fh = cfd;
177 fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
178 tty *ttyp = ptys->get_ttyp ();
179 HANDLE from = ptys->get_handle_nat ();
180 HANDLE input_available_event = ptys->get_input_available_event ();
181 if (ttyp->getpgid () == myself->pgid
182 && GetStdHandle (STD_INPUT_HANDLE) == ptys->get_handle ()
183 && ttyp->pcon_input_state_eq (tty::to_nat) && !force_switch_to)
184 {
185 WaitForSingleObject (ptys->input_mutex, mutex_timeout);
186 fhandler_pty_slave::transfer_input (tty::to_cyg, from, ttyp,
187 input_available_event);
188 ReleaseMutex (ptys->input_mutex);
189 }
190 WaitForSingleObject (ptys->pcon_mutex, INFINITE);
191 ptys->close_pseudoconsole (ttyp, force_switch_to);
192 ReleaseMutex (ptys->pcon_mutex);
193 break;
194 }
195 CloseHandle (h_gdb_process);
196 }
197 }
198
199 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
200 /* CreateProcess() is hooked for GDB etc. */
201 DEF_HOOK (CreateProcessA);
202 DEF_HOOK (CreateProcessW);
203
204 static BOOL WINAPI
205 CreateProcessA_Hooked
206 (LPCSTR n, LPSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
207 BOOL inh, DWORD f, LPVOID e, LPCSTR d,
208 LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
209 {
210 STARTUPINFOEXA siex = {0, };
211 if (si->cb == sizeof (STARTUPINFOEXA))
212 siex = *(STARTUPINFOEXA *)si;
213 else
214 siex.StartupInfo = *si;
215 STARTUPINFOA *siov = &siex.StartupInfo;
216 if (!(si->dwFlags & STARTF_USESTDHANDLES))
217 {
218 siov->dwFlags |= STARTF_USESTDHANDLES;
219 siov->hStdInput = GetStdHandle (STD_INPUT_HANDLE);
220 siov->hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
221 siov->hStdError = GetStdHandle (STD_ERROR_HANDLE);
222 }
223 path_conv path;
224 tmp_pathbuf tp;
225 char *prog =tp.c_get ();
226 if (n)
227 __small_sprintf (prog, "%s", n);
228 else
229 {
230 __small_sprintf (prog, "%s", c);
231 char *p = prog;
232 char *p1;
233 do
234 if ((p1 = strchr (p, ' ')) || (p1 = p + strlen (p)))
235 {
236 p = p1;
237 if (*p == ' ')
238 {
239 *p = '\0';
240 find_exec (prog, path);
241 *p = ' ';
242 p ++;
243 }
244 else if (*p == '\0')
245 find_exec (prog, path);
246 }
247 while (!path.exists() && *p);
248 }
249 const char *argv[] = {"", NULL}; /* Dummy */
250 av av1;
251 av1.setup ("", path, "", 1, argv, false);
252 set_switch_to_pcon (&siov->hStdInput, &siov->hStdOutput, &siov->hStdError,
253 path.iscygexec ());
254 BOOL ret = CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, siov, pi);
255 h_gdb_process = pi->hProcess;
256 DuplicateHandle (GetCurrentProcess (), h_gdb_process,
257 GetCurrentProcess (), &h_gdb_process,
258 0, 0, DUPLICATE_SAME_ACCESS);
259 debug_process = !!(f & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS));
260 if (debug_process)
261 mutex_timeout = 0; /* to avoid deadlock in GDB */
262 if (!atexit_func_registered && !path.iscygexec ())
263 {
264 atexit (atexit_func);
265 atexit_func_registered = true;
266 }
267 return ret;
268 }
269
270 static BOOL WINAPI
271 CreateProcessW_Hooked
272 (LPCWSTR n, LPWSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
273 BOOL inh, DWORD f, LPVOID e, LPCWSTR d,
274 LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
275 {
276 STARTUPINFOEXW siex = {0, };
277 if (si->cb == sizeof (STARTUPINFOEXW))
278 siex = *(STARTUPINFOEXW *)si;
279 else
280 siex.StartupInfo = *si;
281 STARTUPINFOW *siov = &siex.StartupInfo;
282 if (!(si->dwFlags & STARTF_USESTDHANDLES))
283 {
284 siov->dwFlags |= STARTF_USESTDHANDLES;
285 siov->hStdInput = GetStdHandle (STD_INPUT_HANDLE);
286 siov->hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
287 siov->hStdError = GetStdHandle (STD_ERROR_HANDLE);
288 }
289 path_conv path;
290 tmp_pathbuf tp;
291 char *prog =tp.c_get ();
292 if (n)
293 __small_sprintf (prog, "%W", n);
294 else
295 {
296 __small_sprintf (prog, "%W", c);
297 char *p = prog;
298 char *p1;
299 do
300 if ((p1 = strchr (p, ' ')) || (p1 = p + strlen (p)))
301 {
302 p = p1;
303 if (*p == ' ')
304 {
305 *p = '\0';
306 find_exec (prog, path);
307 *p = ' ';
308 p ++;
309 }
310 else if (*p == '\0')
311 find_exec (prog, path);
312 }
313 while (!path.exists() && *p);
314 }
315 const char *argv[] = {"", NULL}; /* Dummy */
316 av av1;
317 av1.setup ("", path, "", 1, argv, false);
318 set_switch_to_pcon (&siov->hStdInput, &siov->hStdOutput, &siov->hStdError,
319 path.iscygexec ());
320 BOOL ret = CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, siov, pi);
321 h_gdb_process = pi->hProcess;
322 DuplicateHandle (GetCurrentProcess (), h_gdb_process,
323 GetCurrentProcess (), &h_gdb_process,
324 0, 0, DUPLICATE_SAME_ACCESS);
325 debug_process = !!(f & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS));
326 if (debug_process)
327 mutex_timeout = 0; /* to avoid deadlock in GDB */
328 if (!atexit_func_registered && !path.iscygexec ())
329 {
330 atexit (atexit_func);
331 atexit_func_registered = true;
332 }
333 return ret;
334 }
335
336 static void
337 convert_mb_str (UINT cp_to, char *ptr_to, size_t *len_to,
338 UINT cp_from, const char *ptr_from, size_t len_from,
339 mbstate_t *mbp)
340 {
341 tmp_pathbuf tp;
342 wchar_t *wbuf = tp.w_get ();
343 int wlen = 0;
344 char *tmpbuf = tp.c_get ();
345 memcpy (tmpbuf, mbp->__value.__wchb, mbp->__count);
346 if (mbp->__count + len_from > NT_MAX_PATH)
347 len_from = NT_MAX_PATH - mbp->__count;
348 memcpy (tmpbuf + mbp->__count, ptr_from, len_from);
349 int total_len = mbp->__count + len_from;
350 mbp->__count = 0;
351 int mblen = 0;
352 for (const char *p = tmpbuf; p < tmpbuf + total_len; p += mblen)
353 /* Max bytes in multibyte char supported is 4. */
354 for (mblen = 1; mblen <= 4; mblen ++)
355 {
356 /* Try conversion */
357 int l = MultiByteToWideChar (cp_from, MB_ERR_INVALID_CHARS,
358 p, mblen,
359 wbuf + wlen, NT_MAX_PATH - wlen);
360 if (l)
361 { /* Conversion Success */
362 wlen += l;
363 break;
364 }
365 else if (mblen == 4)
366 { /* Conversion Fail */
367 l = MultiByteToWideChar (cp_from, 0, p, 1,
368 wbuf + wlen, NT_MAX_PATH - wlen);
369 wlen += l;
370 mblen = 1;
371 break;
372 }
373 else if (p + mblen == tmpbuf + total_len)
374 { /* Multibyte char incomplete */
375 memcpy (mbp->__value.__wchb, p, mblen);
376 mbp->__count = mblen;
377 break;
378 }
379 /* Retry conversion with extended length */
380 }
381 *len_to = WideCharToMultiByte (cp_to, 0, wbuf, wlen,
382 ptr_to, *len_to, NULL, NULL);
383 }
384
385 static bool
386 bytes_available (DWORD& n, HANDLE h)
387 {
388 DWORD navail, nleft;
389 navail = nleft = 0;
390 bool succeeded = PeekNamedPipe (h, NULL, 0, NULL, &navail, &nleft);
391 if (succeeded)
392 /* nleft should always be the right choice unless something has written 0
393 bytes to the pipe. In that pathological case we return the actual number
394 of bytes available in the pipe. See cgf-000008 for more details. */
395 n = nleft ?: navail;
396 else
397 {
398 termios_printf ("PeekNamedPipe(%p) failed, %E", h);
399 n = 0;
400 }
401 debug_only_printf ("n %u, nleft %u, navail %u", n, nleft, navail);
402 return succeeded;
403 }
404
405 bool
406 fhandler_pty_common::bytes_available (DWORD &n)
407 {
408 return ::bytes_available (n, get_handle ());
409 }
410
411 #ifdef DEBUGGING
412 static class mutex_stack
413 {
414 public:
415 const char *fn;
416 int ln;
417 const char *tname;
418 } ostack[100];
419
420 static int osi;
421 #endif /*DEBUGGING*/
422
423 void
424 fhandler_pty_master::flush_to_slave ()
425 {
426 if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON))
427 accept_input ();
428 }
429
430 void
431 fhandler_pty_master::discard_input ()
432 {
433 DWORD bytes_in_pipe;
434 char buf[1024];
435 DWORD n;
436
437 WaitForSingleObject (input_mutex, mutex_timeout);
438 while (::bytes_available (bytes_in_pipe, from_master) && bytes_in_pipe)
439 ReadFile (from_master, buf, sizeof(buf), &n, NULL);
440 ResetEvent (input_available_event);
441 get_ttyp ()->discard_input = true;
442 ReleaseMutex (input_mutex);
443 }
444
445 DWORD
446 fhandler_pty_common::__acquire_output_mutex (const char *fn, int ln,
447 DWORD ms)
448 {
449 if (strace.active ())
450 strace.prntf (_STRACE_TERMIOS, fn, "(%d): pty output_mutex (%p): waiting %d ms", ln, output_mutex, ms);
451 DWORD res = WaitForSingleObject (output_mutex, ms);
452 if (res == WAIT_OBJECT_0)
453 {
454 #ifndef DEBUGGING
455 if (strace.active ())
456 strace.prntf (_STRACE_TERMIOS, fn, "(%d): pty output_mutex: acquired", ln, res);
457 #else
458 ostack[osi].fn = fn;
459 ostack[osi].ln = ln;
460 ostack[osi].tname = mythreadname ();
461 termios_printf ("acquired for %s:%d, osi %d", fn, ln, osi);
462 osi++;
463 #endif
464 }
465 return res;
466 }
467
468 void
469 fhandler_pty_common::__release_output_mutex (const char *fn, int ln)
470 {
471 if (ReleaseMutex (output_mutex))
472 {
473 #ifndef DEBUGGING
474 if (strace.active ())
475 strace.prntf (_STRACE_TERMIOS, fn, "(%d): pty output_mutex(%p) released", ln, output_mutex);
476 #else
477 if (osi > 0)
478 osi--;
479 termios_printf ("released(%p) at %s:%d, osi %d", output_mutex, fn, ln, osi);
480 termios_printf (" for %s:%d (%s)", ostack[osi].fn, ostack[osi].ln, ostack[osi].tname);
481 ostack[osi].ln = -ln;
482 #endif
483 }
484 #ifdef DEBUGGING
485 else if (osi > 0)
486 {
487 system_printf ("couldn't release output mutex but we seem to own it, %E");
488 try_to_debug ();
489 }
490 #endif
491 }
492
493 /* Process pty input. */
494
495 void
496 fhandler_pty_master::doecho (const void *str, DWORD len)
497 {
498 ssize_t towrite = len;
499 acquire_output_mutex (mutex_timeout);
500 if (!process_opost_output (echo_w, str, towrite, true,
501 get_ttyp (), is_nonblocking ()))
502 termios_printf ("Write to echo pipe failed, %E");
503 release_output_mutex ();
504 }
505
506 int
507 fhandler_pty_master::accept_input ()
508 {
509 DWORD bytes_left;
510 int ret = 1;
511
512 WaitForSingleObject (input_mutex, mutex_timeout);
513
514 char *p = rabuf () + raixget ();
515 bytes_left = eat_readahead (-1);
516
517 HANDLE write_to = get_output_handle ();
518 tmp_pathbuf tp;
519 if (to_be_read_from_pcon ()
520 && get_ttyp ()->pcon_input_state == tty::to_nat)
521 {
522 write_to = to_slave_nat;
523
524 UINT cp_to;
525 pinfo pinfo_target = pinfo (get_ttyp ()->invisible_console_pid);
526 DWORD target_pid = 0;
527 if (pinfo_target)
528 target_pid = pinfo_target->dwProcessId;
529 pinfo pinfo_resume = pinfo (myself->ppid);
530 DWORD resume_pid;
531 if (pinfo_resume)
532 resume_pid = pinfo_resume->dwProcessId;
533 else
534 resume_pid = get_console_process_id (myself->dwProcessId, false);
535 if (target_pid && resume_pid)
536 {
537 /* Slave attaches to a different console than master.
538 Therefore reattach here. */
539 acquire_attach_mutex (mutex_timeout);
540 FreeConsole ();
541 AttachConsole (target_pid);
542 cp_to = GetConsoleCP ();
543 FreeConsole ();
544 AttachConsole (resume_pid);
545 release_attach_mutex ();
546 }
547 else
548 cp_to = GetConsoleCP ();
549
550 if (get_ttyp ()->term_code_page != cp_to)
551 {
552 static mbstate_t mbp;
553 char *mbbuf = tp.c_get ();
554 size_t nlen = NT_MAX_PATH;
555 convert_mb_str (cp_to, mbbuf, &nlen,
556 get_ttyp ()->term_code_page, p, bytes_left, &mbp);
557 p = mbbuf;
558 bytes_left = nlen;
559 }
560 }
561
562 if (!bytes_left)
563 {
564 termios_printf ("sending EOF to slave");
565 get_ttyp ()->read_retval = 0;
566 }
567 else
568 {
569 BOOL rc = TRUE;
570 DWORD written = 0;
571
572 paranoid_printf ("about to write %u chars to slave", bytes_left);
573 /* Write line by line for transfer input. */
574 char *p0 = p;
575 char *p1 = p;
576 DWORD n;
577 while ((p1 = (char *) memchr (p0, '\n', bytes_left - (p0 - p)))
578 || (p1 = (char *) memchr (p0, '\r', bytes_left - (p0 - p))))
579 {
580 n = p1 - p0 + 1;
581 rc = WriteFile (write_to, p0, n, &n, NULL);
582 if (rc)
583 written += n;
584 p0 = p1 + 1;
585 }
586 if (rc && (n = bytes_left - (p0 - p)))
587 {
588 rc = WriteFile (write_to, p0, n, &n, NULL);
589 if (rc)
590 written += n;
591 }
592 if (!rc && written == 0)
593 {
594 debug_printf ("error writing to pipe %p %E", write_to);
595 get_ttyp ()->read_retval = -1;
596 puts_readahead (p, bytes_left);
597 ret = -1;
598 }
599 else
600 {
601 get_ttyp ()->read_retval = 1;
602 p += written;
603 bytes_left -= written;
604 if (bytes_left > 0)
605 {
606 debug_printf ("to_slave pipe is full");
607 puts_readahead (p, bytes_left);
608 ret = 0;
609 }
610 }
611 }
612
613 if (write_to == get_output_handle ())
614 SetEvent (input_available_event);
615 ReleaseMutex (input_mutex);
616 return ret;
617 }
618
619 bool
620 fhandler_pty_master::hit_eof ()
621 {
622 if (get_ttyp ()->was_opened && !get_ttyp ()->slave_alive ())
623 {
624 /* We have the only remaining open handle to this pty, and
625 the slave pty has been opened at least once. We treat
626 this as EOF. */
627 termios_printf ("all other handles closed");
628 return 1;
629 }
630 return 0;
631 }
632
633 /* Process pty output requests */
634
635 int
636 fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on)
637 {
638 size_t rlen;
639 char outbuf[OUT_BUFFER_SIZE];
640 DWORD n;
641 DWORD echo_cnt;
642 int rc = 0;
643
644 flush_to_slave ();
645
646 if (len == 0)
647 goto out;
648
649 for (;;)
650 {
651 n = echo_cnt = 0;
652 for (;;)
653 {
654 /* Check echo pipe first. */
655 if (::bytes_available (echo_cnt, echo_r) && echo_cnt > 0)
656 break;
657 if (!bytes_available (n))
658 goto err;
659 if (n)
660 break;
661 if (hit_eof ())
662 {
663 set_errno (EIO);
664 rc = -1;
665 goto out;
666 }
667 /* tclush can finish here. */
668 if (!buf)
669 goto out;
670
671 if (is_nonblocking ())
672 {
673 set_errno (EAGAIN);
674 rc = -1;
675 goto out;
676 }
677 pthread_testcancel ();
678 if (cygwait (NULL, 10, cw_sig_eintr) == WAIT_SIGNALED
679 && !_my_tls.call_signal_handler ())
680 {
681 set_errno (EINTR);
682 rc = -1;
683 goto out;
684 }
685 flush_to_slave ();
686 }
687
688 /* Set RLEN to the number of bytes to read from the pipe. */
689 rlen = len;
690
691 char *optr;
692 optr = buf;
693 if (pktmode_on && buf)
694 {
695 *optr++ = TIOCPKT_DATA;
696 rlen -= 1;
697 }
698
699 if (rlen == 0)
700 {
701 rc = optr - buf;
702 goto out;
703 }
704
705 if (rlen > sizeof outbuf)
706 rlen = sizeof outbuf;
707
708 /* If echo pipe has data (something has been typed or pasted), prefer
709 it over slave output. */
710 if (echo_cnt > 0)
711 {
712 if (!ReadFile (echo_r, outbuf, rlen, &n, NULL))
713 {
714 termios_printf ("ReadFile on echo pipe failed, %E");
715 goto err;
716 }
717 }
718 else if (!ReadFile (get_handle (), outbuf, rlen, &n, NULL))
719 {
720 termios_printf ("ReadFile failed, %E");
721 goto err;
722 }
723
724 termios_printf ("bytes read %u", n);
725
726 if (!buf || ((get_ttyp ()->ti.c_lflag & FLUSHO)
727 && !get_ttyp ()->mask_flusho))
728 continue; /* Discard read data */
729
730 memcpy (optr, outbuf, n);
731 optr += n;
732 rc = optr - buf;
733 break;
734
735 err:
736 if (GetLastError () == ERROR_BROKEN_PIPE)
737 rc = 0;
738 else
739 {
740 __seterrno ();
741 rc = -1;
742 }
743 break;
744 }
745
746 out:
747 if (buf)
748 set_mask_flusho (false);
749 termios_printf ("returning %d", rc);
750 return rc;
751 }
752
753 /* pty slave stuff */
754
755 fhandler_pty_slave::fhandler_pty_slave (int unit)
756 : fhandler_pty_common (), inuse (NULL), output_handle_nat (NULL),
757 io_handle_nat (NULL), slave_reading (NULL), num_reader (0)
758 {
759 if (unit >= 0)
760 dev ().parse (DEV_PTYS_MAJOR, unit);
761 }
762
763 int
764 fhandler_pty_slave::open (int flags, mode_t)
765 {
766 HANDLE pty_owner;
767 HANDLE from_master_nat_local, from_master_local;
768 HANDLE to_master_nat_local, to_master_local;
769 HANDLE *handles[] =
770 {
771 &from_master_nat_local, &input_available_event, &input_mutex, &inuse,
772 &output_mutex, &to_master_nat_local, &pty_owner, &to_master_local,
773 &from_master_local, &pcon_mutex,
774 NULL
775 };
776
777 for (HANDLE **h = handles; *h; h++)
778 **h = NULL;
779
780 _tc = cygwin_shared->tty[get_minor ()];
781
782 tcinit (false);
783
784 cygwin_shared->tty.attach (get_minor ());
785
786 /* Create synchronisation events */
787 char buf[MAX_PATH];
788
789 const char *errmsg = NULL;
790
791 if (!(output_mutex = get_ttyp ()->open_output_mutex (MAXIMUM_ALLOWED)))
792 {
793 errmsg = "open output mutex failed, %E";
794 goto err;
795 }
796 if (!(input_mutex = get_ttyp ()->open_input_mutex (MAXIMUM_ALLOWED)))
797 {
798 errmsg = "open input mutex failed, %E";
799 goto err;
800 }
801 if (!(pcon_mutex = get_ttyp ()->open_mutex (PCON_MUTEX, MAXIMUM_ALLOWED)))
802 {
803 errmsg = "open pcon mutex failed, %E";
804 goto err;
805 }
806 shared_name (buf, INPUT_AVAILABLE_EVENT, get_minor ());
807 if (!(input_available_event = OpenEvent (MAXIMUM_ALLOWED, TRUE, buf)))
808 {
809 errmsg = "open input event failed, %E";
810 goto err;
811 }
812
813 /* FIXME: Needs a method to eliminate tty races */
814 {
815 /* Create security attribute. Default permissions are 0620. */
816 security_descriptor sd;
817 sd.malloc (sizeof (SECURITY_DESCRIPTOR));
818 RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
819 SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE };
820 if (!create_object_sd_from_attribute (myself->uid, myself->gid,
821 S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP,
822 sd))
823 sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) sd;
824 acquire_output_mutex (mutex_timeout);
825 inuse = get_ttyp ()->create_inuse (&sa);
826 get_ttyp ()->was_opened = true;
827 release_output_mutex ();
828 }
829
830 if (!get_ttyp ()->from_master_nat () || !get_ttyp ()->from_master ()
831 || !get_ttyp ()->to_master_nat () || !get_ttyp ()->to_master ())
832 {
833 errmsg = "pty handles have been closed";
834 set_errno (EACCES);
835 goto err_no_errno;
836 }
837
838 /* Three case for duplicating the pipe handles:
839 - Either we're the master. In this case, just duplicate the handles.
840 - Or, we have the right to open the master process for handle duplication.
841 In this case, just duplicate the handles.
842 - Or, we have to ask the master process itself. In this case, send our
843 pid to the master process and check the reply. The reply contains
844 either the handles, or an error code which tells us why we didn't
845 get the handles. */
846 if (myself->pid == get_ttyp ()->master_pid)
847 {
848 /* This is the most common case, just calling openpty. */
849 termios_printf ("dup handles within myself.");
850 pty_owner = GetCurrentProcess ();
851 }
852 else
853 {
854 pinfo p (get_ttyp ()->master_pid);
855 if (!p)
856 termios_printf ("*** couldn't find pty master");
857 else
858 {
859 pty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId);
860 if (pty_owner)
861 termios_printf ("dup handles directly since I'm the owner");
862 }
863 }
864 if (pty_owner)
865 {
866 if (!DuplicateHandle (pty_owner, get_ttyp ()->from_master_nat (),
867 GetCurrentProcess (),
868 &from_master_nat_local, 0, TRUE,
869 DUPLICATE_SAME_ACCESS))
870 {
871 termios_printf ("can't duplicate input from %u/%p, %E",
872 get_ttyp ()->master_pid,
873 get_ttyp ()->from_master_nat ());
874 __seterrno ();
875 goto err_no_msg;
876 }
877 if (!DuplicateHandle (pty_owner, get_ttyp ()->from_master (),
878 GetCurrentProcess (),
879 &from_master_local, 0, TRUE,
880 DUPLICATE_SAME_ACCESS))
881 {
882 termios_printf ("can't duplicate input from %u/%p, %E",
883 get_ttyp ()->master_pid,
884 get_ttyp ()->from_master ());
885 __seterrno ();
886 goto err_no_msg;
887 }
888 if (!DuplicateHandle (pty_owner, get_ttyp ()->to_master_nat (),
889 GetCurrentProcess (),
890 &to_master_nat_local, 0, TRUE,
891 DUPLICATE_SAME_ACCESS))
892 {
893 errmsg = "can't duplicate output, %E";
894 goto err;
895 }
896 if (!DuplicateHandle (pty_owner, get_ttyp ()->to_master (),
897 GetCurrentProcess (),
898 &to_master_local, 0, TRUE,
899 DUPLICATE_SAME_ACCESS))
900 {
901 errmsg = "can't duplicate output for cygwin, %E";
902 goto err;
903 }
904 if (pty_owner != GetCurrentProcess ())
905 CloseHandle (pty_owner);
906 }
907 else
908 {
909 pipe_request req = { GetCurrentProcessId () };
910 pipe_reply repl;
911 DWORD len;
912
913 __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
914 &cygheap->installation_key, get_minor ());
915 termios_printf ("dup handles via master control pipe %s", buf);
916 if (!CallNamedPipe (buf, &req, sizeof req, &repl, sizeof repl,
917 &len, 500))
918 {
919 errmsg = "can't call master, %E";
920 goto err;
921 }
922 from_master_nat_local = repl.from_master_nat;
923 from_master_local = repl.from_master;
924 to_master_nat_local = repl.to_master_nat;
925 to_master_local = repl.to_master;
926 if (!from_master_nat_local || !from_master_local
927 || !to_master_nat_local || !to_master_local)
928 {
929 SetLastError (repl.error);
930 errmsg = "error duplicating pipes, %E";
931 goto err;
932 }
933 }
934 VerifyHandle (from_master_nat_local);
935 VerifyHandle (from_master_local);
936 VerifyHandle (to_master_nat_local);
937 VerifyHandle (to_master_local);
938
939 termios_printf ("duplicated from_master_nat %p->%p from pty_owner",
940 get_ttyp ()->from_master_nat (), from_master_nat_local);
941 termios_printf ("duplicated from_master %p->%p from pty_owner",
942 get_ttyp ()->from_master (), from_master_local);
943 termios_printf ("duplicated to_master_nat %p->%p from pty_owner",
944 get_ttyp ()->to_master_nat (), to_master_nat_local);
945 termios_printf ("duplicated to_master %p->%p from pty_owner",
946 get_ttyp ()->to_master (), to_master_local);
947
948 set_handle_nat (from_master_nat_local);
949 set_handle (from_master_local);
950 set_output_handle_nat (to_master_nat_local);
951 set_output_handle (to_master_local);
952
953 if (_major (myself->ctty) == DEV_CONS_MAJOR
954 && !(!pinfo (myself->ppid) && getenv ("ConEmuPID")))
955 /* This process is supposed to be a master process which is
956 running on console. Invisible console will be created in
957 primary slave process to prevent overriding code page
958 of root console by setup_locale(). */
959 /* ... except for ConEmu cygwin-connector in which this
960 code does not work as expected because it calls Win32
961 API directly rather than cygwin read()/write(). Due to
962 this behaviour, protection based on attach_mutex does
963 not take effect. */
964 get_ttyp ()->need_invisible_console = true;
965 else
966 fhandler_console::need_invisible ();
967
968 set_open_status ();
969 return 1;
970
971 err:
972 if (GetLastError () == ERROR_FILE_NOT_FOUND)
973 set_errno (ENXIO);
974 else
975 __seterrno ();
976 err_no_errno:
977 termios_printf (errmsg);
978 err_no_msg:
979 for (HANDLE **h = handles; *h; h++)
980 if (**h && **h != INVALID_HANDLE_VALUE)
981 CloseHandle (**h);
982 return 0;
983 }
984
985 bool
986 fhandler_pty_slave::open_setup (int flags)
987 {
988 set_flags ((flags & ~O_TEXT) | O_BINARY);
989 myself->set_ctty (this, flags);
990 report_tty_counts (this, "opened", "");
991 return fhandler_base::open_setup (flags);
992 }
993
994 void
995 fhandler_pty_slave::cleanup ()
996 {
997 /* This used to always call fhandler_pty_common::close when we were execing
998 but that caused multiple closes of the handles associated with this pty.
999 Since close_all_files is not called until after the cygwin process has
1000 synced or before a non-cygwin process has exited, it should be safe to
1001 just close this normally. cgf 2006-05-20 */
1002 report_tty_counts (this, "closed", "");
1003 fhandler_base::cleanup ();
1004 }
1005
1006 int
1007 fhandler_pty_slave::close ()
1008 {
1009 termios_printf ("closing last open %s handle", ttyname ());
1010 if (inuse && !CloseHandle (inuse))
1011 termios_printf ("CloseHandle (inuse), %E");
1012 if (!ForceCloseHandle (input_available_event))
1013 termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event);
1014 if (!ForceCloseHandle (get_output_handle_nat ()))
1015 termios_printf ("CloseHandle (get_output_handle_nat ()<%p>), %E",
1016 get_output_handle_nat ());
1017 if (!ForceCloseHandle (get_handle_nat ()))
1018 termios_printf ("CloseHandle (get_handle_nat ()<%p>), %E",
1019 get_handle_nat ());
1020 if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
1021 fhandler_console::free_console (); /* assumes that we are the last pty closer */
1022 fhandler_pty_common::close ();
1023 if (!ForceCloseHandle (output_mutex))
1024 termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
1025 return 0;
1026 }
1027
1028 int
1029 fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
1030 {
1031 int flags = 0;
1032
1033 a &= GENERIC_READ | GENERIC_WRITE;
1034 if (a == GENERIC_READ)
1035 flags = O_RDONLY;
1036 if (a == GENERIC_WRITE)
1037 flags = O_WRONLY;
1038 if (a == (GENERIC_READ | GENERIC_WRITE))
1039 flags = O_RDWR;
1040
1041 int ret = open_with_arch (flags);
1042
1043 if (ret && !cygwin_finished_initializing && !being_debugged ())
1044 {
1045 /* This only occurs when called from dtable::init_std_file_from_handle
1046 We have been started from a non-Cygwin process. So we should become
1047 pty process group leader.
1048 TODO: Investigate how SIGTTIN should be handled with pure-windows
1049 programs. */
1050 pinfo p (tc ()->getpgid ());
1051 /* We should only grab this when the process group owner for this
1052 pty is a non-cygwin process or we've been started directly
1053 from a non-Cygwin process with no Cygwin ancestry. */
1054 if (!p || ISSTATE (p, PID_NOTCYGWIN))
1055 {
1056 termios_printf ("Setting process group leader to %d since %W(%d) is not a cygwin process",
1057 myself->pgid, p->progname, p->pid);
1058 tc ()->setpgid (myself->pgid);
1059 }
1060 }
1061
1062 if (h != INVALID_HANDLE_VALUE)
1063 CloseHandle (h); /* Reopened by open */
1064
1065 return ret;
1066 }
1067
1068 void
1069 fhandler_pty_slave::set_switch_to_pcon (void)
1070 {
1071 if (!isHybrid)
1072 {
1073 isHybrid = true;
1074 setup_locale ();
1075 myself->exec_dwProcessId = myself->dwProcessId;
1076 myself->process_state |= PID_NEW_PG; /* Marker for pcon_fg */
1077 bool nopcon = (disable_pcon || !term_has_pcon_cap (NULL));
1078 WaitForSingleObject (pcon_mutex, INFINITE);
1079 bool pcon_enabled = setup_pseudoconsole (nopcon);
1080 ReleaseMutex (pcon_mutex);
1081 if (!pcon_enabled && get_ttyp ()->getpgid () == myself->pgid
1082 && GetStdHandle (STD_INPUT_HANDLE) == get_handle ()
1083 && get_ttyp ()->pcon_input_state_eq (tty::to_cyg))
1084 {
1085 WaitForSingleObject (input_mutex, mutex_timeout);
1086 transfer_input (tty::to_nat, get_handle (), get_ttyp (),
1087 input_available_event);
1088 ReleaseMutex (input_mutex);
1089 }
1090 }
1091 }
1092
1093 inline static bool
1094 pcon_pid_alive (DWORD pid)
1095 {
1096 if (pid == 0)
1097 return false;
1098 HANDLE h = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
1099 if (h == NULL)
1100 return false;
1101 DWORD exit_code;
1102 BOOL r = GetExitCodeProcess (h, &exit_code);
1103 CloseHandle (h);
1104 if (r && exit_code == STILL_ACTIVE)
1105 return true;
1106 return false;
1107 }
1108
1109 inline static bool
1110 pcon_pid_self (DWORD pid)
1111 {
1112 return (pid == myself->exec_dwProcessId);
1113 }
1114
1115 void
1116 fhandler_pty_slave::reset_switch_to_pcon (void)
1117 {
1118 if (h_gdb_process)
1119 {
1120 if (WaitForSingleObject (h_gdb_process, 0) == WAIT_TIMEOUT)
1121 {
1122 if (isHybrid)
1123 get_ttyp ()->wait_pcon_fwd (false);
1124 }
1125 else
1126 {
1127 CloseHandle (h_gdb_process);
1128 h_gdb_process = NULL;
1129 mutex_timeout = INFINITE;
1130 if (isHybrid)
1131 {
1132 if (get_ttyp ()->getpgid () == myself->pgid
1133 && GetStdHandle (STD_INPUT_HANDLE) == get_handle ()
1134 && get_ttyp ()->pcon_input_state_eq (tty::to_nat))
1135 {
1136 WaitForSingleObject (input_mutex, mutex_timeout);
1137 transfer_input (tty::to_cyg, get_handle_nat (), get_ttyp (),
1138 input_available_event);
1139 ReleaseMutex (input_mutex);
1140 }
1141 if (get_ttyp ()->master_is_running_as_service
1142 && get_ttyp ()->pcon_activated)
1143 /* If the master is running as service, re-attaching to
1144 the console of the parent process will fail.
1145 Therefore, never close pseudo console here. */
1146 return;
1147 bool need_restore_handles = get_ttyp ()->pcon_activated;
1148 WaitForSingleObject (pcon_mutex, INFINITE);
1149 close_pseudoconsole (get_ttyp ());
1150 ReleaseMutex (pcon_mutex);
1151 if (need_restore_handles)
1152 {
1153 pinfo p (get_ttyp ()->master_pid);
1154 HANDLE pty_owner =
1155 OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId);
1156 if (pty_owner)
1157 {
1158 CloseHandle (get_handle_nat ());
1159 DuplicateHandle (pty_owner,
1160 get_ttyp ()->from_master_nat (),
1161 GetCurrentProcess (), &get_handle_nat (),
1162 0, TRUE, DUPLICATE_SAME_ACCESS);
1163 CloseHandle (get_output_handle_nat ());
1164 DuplicateHandle (pty_owner,
1165 get_ttyp ()->to_master_nat (),
1166 GetCurrentProcess (),
1167 &get_output_handle_nat (),
1168 0, TRUE, DUPLICATE_SAME_ACCESS);
1169 CloseHandle (pty_owner);
1170 }
1171 else
1172 {
1173 char pipe[MAX_PATH];
1174 __small_sprintf (pipe,
1175 "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
1176 &cygheap->installation_key, get_minor ());
1177 pipe_request req = { GetCurrentProcessId () };
1178 pipe_reply repl;
1179 DWORD len;
1180 if (!CallNamedPipe (pipe, &req, sizeof req,
1181 &repl, sizeof repl, &len, 500))
1182 return; /* What can we do? */
1183 CloseHandle (get_handle_nat ());
1184 set_handle_nat (repl.from_master_nat);
1185 CloseHandle (get_output_handle_nat ());
1186 set_output_handle_nat (repl.to_master_nat);
1187 }
1188 }
1189 myself->exec_dwProcessId = 0;
1190 myself->process_state &= ~PID_NEW_PG;
1191 isHybrid = false;
1192 }
1193 }
1194 }
1195 if (isHybrid)
1196 return;
1197 if (get_ttyp ()->pcon_start)
1198 return;
1199 DWORD wait_ret = WaitForSingleObject (pcon_mutex, mutex_timeout);
1200 if (wait_ret == WAIT_TIMEOUT)
1201 return;
1202 if (!pcon_pid_self (get_ttyp ()->pcon_pid)
1203 && pcon_pid_alive (get_ttyp ()->pcon_pid))
1204 {
1205 /* There is a process which is grabbing pseudo console. */
1206 if (!to_be_read_from_pcon ()
1207 && get_ttyp ()->pcon_input_state_eq (tty::to_nat))
1208 {
1209 if (get_ttyp ()->pcon_activated)
1210 {
1211 HANDLE pcon_owner =
1212 OpenProcess (PROCESS_DUP_HANDLE, FALSE, get_ttyp ()->pcon_pid);
1213 if (pcon_owner)
1214 {
1215 pinfo pinfo_resume = pinfo (myself->ppid);
1216 DWORD resume_pid;
1217 if (pinfo_resume)
1218 resume_pid = pinfo_resume->dwProcessId;
1219 else
1220 resume_pid =
1221 get_console_process_id (myself->dwProcessId, false);
1222 if (resume_pid)
1223 {
1224 HANDLE h_pcon_in;
1225 DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_in,
1226 GetCurrentProcess (), &h_pcon_in,
1227 0, TRUE, DUPLICATE_SAME_ACCESS);
1228 FreeConsole ();
1229 AttachConsole (get_ttyp ()->pcon_pid);
1230 WaitForSingleObject (input_mutex, mutex_timeout);
1231 transfer_input (tty::to_cyg, h_pcon_in, get_ttyp (),
1232 input_available_event);
1233 ReleaseMutex (input_mutex);
1234 FreeConsole ();
1235 AttachConsole (resume_pid);
1236 CloseHandle (h_pcon_in);
1237 }
1238 CloseHandle (pcon_owner);
1239 }
1240 }
1241 else if (!get_ttyp ()->pcon_fg (get_ttyp ()->getpgid ())
1242 && get_ttyp ()->switch_to_pcon_in)
1243 {
1244 WaitForSingleObject (input_mutex, mutex_timeout);
1245 transfer_input (tty::to_cyg, get_handle_nat (), get_ttyp (),
1246 input_available_event);
1247 ReleaseMutex (input_mutex);
1248 }
1249 }
1250 ReleaseMutex (pcon_mutex);
1251 return;
1252 }
1253 /* This input transfer is needed if non-cygwin app is terminated
1254 by Ctrl-C or killed. */
1255 WaitForSingleObject (input_mutex, mutex_timeout);
1256 if (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->pcon_activated
1257 && get_ttyp ()->pcon_input_state_eq (tty::to_nat))
1258 transfer_input (tty::to_cyg, get_handle_nat (), get_ttyp (),
1259 input_available_event);
1260 ReleaseMutex (input_mutex);
1261 get_ttyp ()->pcon_input_state = tty::to_cyg;
1262 get_ttyp ()->pcon_pid = 0;
1263 get_ttyp ()->switch_to_pcon_in = false;
1264 get_ttyp ()->pcon_activated = false;
1265 ReleaseMutex (pcon_mutex);
1266 }
1267
1268 ssize_t __stdcall
1269 fhandler_pty_slave::write (const void *ptr, size_t len)
1270 {
1271 ssize_t towrite = len;
1272
1273 bg_check_types bg = bg_check (SIGTTOU);
1274 if (bg <= bg_eof)
1275 return (ssize_t) bg;
1276
1277 termios_printf ("pty%d, write(%p, %lu)", get_minor (), ptr, len);
1278
1279 push_process_state process_state (PID_TTYOU);
1280
1281 reset_switch_to_pcon ();
1282
1283 acquire_output_mutex (mutex_timeout);
1284 if (!process_opost_output (get_output_handle (), ptr, towrite, false,
1285 get_ttyp (), is_nonblocking ()))
1286 {
1287 DWORD err = GetLastError ();
1288 termios_printf ("WriteFile failed, %E");
1289 switch (err)
1290 {
1291 case ERROR_NO_DATA:
1292 err = ERROR_IO_DEVICE;
1293 fallthrough;
1294 default:
1295 __seterrno_from_win_error (err);
1296 }
1297 towrite = -1;
1298 }
1299 release_output_mutex ();
1300
1301 return towrite;
1302 }
1303
1304 void
1305 fhandler_pty_slave::mask_switch_to_pcon_in (bool mask, bool xfer)
1306 {
1307 char name[MAX_PATH];
1308 shared_name (name, TTY_SLAVE_READING, get_minor ());
1309 HANDLE masked = OpenEvent (READ_CONTROL, FALSE, name);
1310 CloseHandle (masked);
1311
1312 WaitForSingleObject (input_mutex, mutex_timeout);
1313 if (mask)
1314 {
1315 if (InterlockedIncrement (&num_reader) == 1)
1316 slave_reading = CreateEvent (&sec_none_nih, TRUE, FALSE, name);
1317 }
1318 else if (InterlockedDecrement (&num_reader) == 0)
1319 CloseHandle (slave_reading);
1320
1321 /* This is needed when cygwin-app is started from non-cygwin app if
1322 pseudo console is disabled. */
1323 bool need_xfer = get_ttyp ()->pcon_fg (get_ttyp ()->getpgid ())
1324 && get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->pcon_activated;
1325
1326 /* In GDB, transfer input based on setpgid() does not work because
1327 GDB may not set terminal process group properly. Therefore,
1328 transfer input here if isHybrid is set. */
1329 bool need_gdb_xfer =
1330 isHybrid && GetStdHandle (STD_INPUT_HANDLE) == get_handle ();
1331 if (!!masked != mask && xfer && (need_gdb_xfer || need_xfer))
1332 {
1333 if (mask && get_ttyp ()->pcon_input_state_eq (tty::to_nat))
1334 transfer_input (tty::to_cyg, get_handle_nat (), get_ttyp (),
1335 input_available_event);
1336 else if (!mask && get_ttyp ()->pcon_input_state_eq (tty::to_cyg))
1337 transfer_input (tty::to_nat, get_handle (), get_ttyp (),
1338 input_available_event);
1339 }
1340 ReleaseMutex (input_mutex);
1341 }
1342
1343 bool
1344 fhandler_pty_common::to_be_read_from_pcon (void)
1345 {
1346 if (!get_ttyp ()->switch_to_pcon_in)
1347 return false;
1348
1349 char name[MAX_PATH];
1350 shared_name (name, TTY_SLAVE_READING, get_minor ());
1351 HANDLE masked = OpenEvent (READ_CONTROL, FALSE, name);
1352 CloseHandle (masked);
1353
1354 if (masked) /* The foreground process is cygwin process */
1355 return false;
1356
1357 if (!pinfo (get_ttyp ()->getpgid ()))
1358 /* GDB may set invalid process group for non-cygwin process. */
1359 return true;
1360
1361 return get_ttyp ()->pcon_fg (get_ttyp ()->getpgid ());
1362 }
1363
1364 void __reg3
1365 fhandler_pty_slave::read (void *ptr, size_t& len)
1366 {
1367 ssize_t totalread = 0;
1368 int vmin = 0;
1369 int vtime = 0; /* Initialized to prevent -Wuninitialized warning */
1370 size_t readlen;
1371 DWORD bytes_in_pipe;
1372 char buf[INP_BUFFER_SIZE];
1373 DWORD time_to_wait;
1374 char *ptr0 = (char *) ptr;
1375
1376 bg_check_types bg = bg_check (SIGTTIN);
1377 if (bg <= bg_eof)
1378 {
1379 len = (size_t) bg;
1380 return;
1381 }
1382
1383 termios_printf ("read(%p, %lu) handle %p", ptr, len, get_handle ());
1384
1385 push_process_state process_state (PID_TTYIN);
1386
1387 if (ptr) /* Indicating not tcflush(). */
1388 {
1389 mask_switch_to_pcon_in (true, true);
1390 reset_switch_to_pcon ();
1391 }
1392
1393 if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
1394 time_to_wait = 0;
1395 else if ((get_ttyp ()->ti.c_lflag & ICANON))
1396 time_to_wait = INFINITE;
1397 else
1398 {
1399 vmin = get_ttyp ()->ti.c_cc[VMIN];
1400 if (vmin > INP_BUFFER_SIZE)
1401 vmin = INP_BUFFER_SIZE;
1402 vtime = get_ttyp ()->ti.c_cc[VTIME];
1403 if (vmin < 0)
1404 vmin = 0;
1405 if (vtime < 0)
1406 vtime = 0;
1407 if (!vmin && !vtime)
1408 time_to_wait = 0;
1409 else
1410 time_to_wait = !vtime ? INFINITE : 100 * vtime;
1411 }
1412
1413 wait_retry:
1414 while (len)
1415 {
1416 switch (cygwait (input_available_event, time_to_wait))
1417 {
1418 case WAIT_OBJECT_0:
1419 break;
1420 case WAIT_SIGNALED:
1421 if (totalread > 0)
1422 goto out;
1423 termios_printf ("wait catched signal");
1424 set_sig_errno (EINTR);
1425 totalread = -1;
1426 goto out;
1427 case WAIT_CANCELED:
1428 process_state.pop ();
1429 pthread::static_cancel_self ();
1430 /*NOTREACHED*/
1431 case WAIT_TIMEOUT:
1432 termios_printf ("wait timed out, time_to_wait %u", time_to_wait);
1433 /* No error condition when called from tcflush. */
1434 if (!totalread && ptr)
1435 {
1436 set_sig_errno (EAGAIN);
1437 totalread = -1;
1438 }
1439 goto out;
1440 default:
1441 termios_printf ("wait for input event failed, %E");
1442 if (!totalread)
1443 {
1444 __seterrno ();
1445 totalread = -1;
1446 }
1447 goto out;
1448 }
1449 /* Now that we know that input is available we have to grab the
1450 input mutex. */
1451 switch (cygwait (input_mutex, 1000))
1452 {
1453 case WAIT_OBJECT_0:
1454 case WAIT_ABANDONED_0:
1455 break;
1456 case WAIT_SIGNALED:
1457 if (totalread > 0)
1458 goto out;
1459 termios_printf ("wait for mutex caught signal");
1460 set_sig_errno (EINTR);
1461 totalread = -1;
1462 goto out;
1463 case WAIT_CANCELED:
1464 process_state.pop ();
1465 pthread::static_cancel_self ();
1466 /*NOTREACHED*/
1467 case WAIT_TIMEOUT:
1468 termios_printf ("failed to acquire input mutex after input event "
1469 "arrived");
1470 /* If we have a timeout, we can simply handle this failure to
1471 grab the mutex as an EAGAIN situation. Otherwise, if this
1472 is an infinitely blocking read, restart the loop. */
1473 if (time_to_wait != INFINITE)
1474 {
1475 if (!totalread)
1476 {
1477 set_sig_errno (EAGAIN);
1478 totalread = -1;
1479 }
1480 goto out;
1481 }
1482 continue;
1483 default:
1484 termios_printf ("wait for input mutex failed, %E");
1485 if (!totalread)
1486 {
1487 __seterrno ();
1488 totalread = -1;
1489 }
1490 goto out;
1491 }
1492 if (!IsEventSignalled (input_available_event))
1493 { /* Maybe another thread has processed input. */
1494 ReleaseMutex (input_mutex);
1495 goto wait_retry;
1496 }
1497
1498 if (!bytes_available (bytes_in_pipe))
1499 {
1500 ReleaseMutex (input_mutex);
1501 set_errno (EIO);
1502 totalread = -1;
1503 goto out;
1504 }
1505
1506 if (ptr && !bytes_in_pipe && !vmin && !time_to_wait)
1507 {
1508 ReleaseMutex (input_mutex);
1509 mask_switch_to_pcon_in (false, false);
1510 len = (size_t) bytes_in_pipe;
1511 return;
1512 }
1513
1514 readlen = bytes_in_pipe ? MIN (len, sizeof (buf)) : 0;
1515 if (get_ttyp ()->ti.c_lflag & ICANON && ptr)
1516 readlen = MIN (bytes_in_pipe, readlen);
1517
1518 #if 0
1519 /* Why on earth is the read length reduced to vmin, even if more bytes
1520 are available *and* len is bigger *and* the local buf is big enough?
1521 Disable this code for now, it looks like a remnant of old. */
1522 if (ptr && vmin && readlen > (unsigned) vmin)
1523 readlen = vmin;
1524 #endif
1525
1526 DWORD n = 0;
1527 if (readlen)
1528 {
1529 termios_printf ("reading %lu bytes (vtime %d)", readlen, vtime);
1530 if (!ReadFile (get_handle (), buf, readlen, &n, NULL))
1531 {
1532 termios_printf ("read failed, %E");
1533 ReleaseMutex (input_mutex);
1534 set_errno (EIO);
1535 totalread = -1;
1536 goto out;
1537 }
1538 else
1539 {
1540 /* MSDN states that 5th prameter can be used to determine total
1541 number of bytes in pipe, but for some reason this number doesn't
1542 change after successful read. So we have to peek into the pipe
1543 again to see if input is still available */
1544 if (!bytes_available (bytes_in_pipe))
1545 {
1546 ReleaseMutex (input_mutex);
1547 set_errno (EIO);
1548 totalread = -1;
1549 goto out;
1550 }
1551 if (n)
1552 {
1553 if (!(!ptr && len == UINT_MAX)) /* not tcflush() */
1554 len -= n;
1555 totalread += n;
1556 if (ptr)
1557 {
1558 memcpy (ptr, buf, n);
1559 ptr = (char *) ptr + n;
1560 }
1561 }
1562 }
1563 }
1564
1565 if (!bytes_in_pipe)
1566 ResetEvent (input_available_event);
1567
1568 ReleaseMutex (input_mutex);
1569
1570 if (!ptr)
1571 {
1572 if (!bytes_in_pipe)
1573 break;
1574 continue;
1575 }
1576
1577 if (get_ttyp ()->read_retval < 0) // read error
1578 {
1579 set_errno (-get_ttyp ()->read_retval);
1580 totalread = -1;
1581 break;
1582 }
1583 if (get_ttyp ()->read_retval == 0) //EOF
1584 {
1585 termios_printf ("saw EOF");
1586 break;
1587 }
1588 if (get_ttyp ()->ti.c_lflag & ICANON || is_nonblocking ())
1589 break;
1590 if (vmin && totalread >= vmin)
1591 break;
1592
1593 /* vmin == 0 && vtime == 0:
1594 * we've already read all input, if any, so return immediately
1595 * vmin == 0 && vtime > 0:
1596 * we've waited for input 10*vtime ms in WFSO(input_available_event),
1597 * no matter whether any input arrived, we shouldn't wait any longer,
1598 * so return immediately
1599 * vmin > 0 && vtime == 0:
1600 * here, totalread < vmin, so continue waiting until more data
1601 * arrive
1602 * vmin > 0 && vtime > 0:
1603 * similar to the previous here, totalread < vmin, and timer
1604 * hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT,
1605 * so "restart timer" and wait until more data arrive
1606 */
1607
1608 if (vmin == 0)
1609 break;
1610 }
1611 out:
1612 termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
1613 len = (size_t) totalread;
1614 if (ptr0)
1615 { /* Not tcflush() */
1616 bool saw_eol = totalread > 0 && strchr ("\r\n", ptr0[totalread -1]);
1617 mask_switch_to_pcon_in (false, saw_eol || len == 0);
1618 }
1619 }
1620
1621 int
1622 fhandler_pty_slave::dup (fhandler_base *child, int flags)
1623 {
1624 /* This code was added in Oct 2001 for some undisclosed reason.
1625 However, setting the controlling tty on a dup causes rxvt to
1626 hang when the parent does a dup since the controlling pgid changes.
1627 Specifically testing for -2 (ctty has been setsid'ed) works around
1628 this problem. However, it's difficult to see scenarios in which you
1629 have a dup'able fd, no controlling tty, and not having run setsid.
1630 So, we might want to consider getting rid of the set_ctty in tty-like dup
1631 methods entirely at some point */
1632 if (myself->ctty != -2)
1633 myself->set_ctty (this, flags);
1634 report_tty_counts (child, "duped slave", "");
1635 return 0;
1636 }
1637
1638 int
1639 fhandler_pty_master::dup (fhandler_base *child, int)
1640 {
1641 report_tty_counts (child, "duped master", "");
1642 return 0;
1643 }
1644
1645 int
1646 fhandler_pty_slave::tcgetattr (struct termios *t)
1647 {
1648 reset_switch_to_pcon ();
1649 *t = get_ttyp ()->ti;
1650
1651 /* Workaround for rlwrap */
1652 cygheap_fdenum cfd (false);
1653 while (cfd.next () >= 0)
1654 if (cfd->get_major () == DEV_PTYM_MAJOR
1655 && cfd->get_minor () == get_minor ())
1656 {
1657 if (get_ttyp ()->pcon_start)
1658 t->c_lflag &= ~(ICANON | ECHO);
1659 if (get_ttyp ()->pcon_activated)
1660 t->c_iflag &= ~ICRNL;
1661 break;
1662 }
1663 return 0;
1664 }
1665
1666 int
1667 fhandler_pty_slave::tcsetattr (int, const struct termios *t)
1668 {
1669 reset_switch_to_pcon ();
1670 acquire_output_mutex (mutex_timeout);
1671 get_ttyp ()->ti = *t;
1672 release_output_mutex ();
1673 return 0;
1674 }
1675
1676 int
1677 fhandler_pty_slave::tcflush (int queue)
1678 {
1679 int ret = 0;
1680
1681 termios_printf ("tcflush(%d) handle %p", queue, get_handle ());
1682
1683 reset_switch_to_pcon ();
1684
1685 if (queue == TCIFLUSH || queue == TCIOFLUSH)
1686 {
1687 size_t len = UINT_MAX;
1688 read (NULL, len);
1689 ret = ((int) len) >= 0 ? 0 : -1;
1690 }
1691 if (queue == TCOFLUSH || queue == TCIOFLUSH)
1692 {
1693 /* do nothing for now. */
1694 }
1695
1696 termios_printf ("%d=tcflush(%d)", ret, queue);
1697 return ret;
1698 }
1699
1700 int
1701 fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
1702 {
1703 termios_printf ("ioctl (%x)", cmd);
1704 reset_switch_to_pcon ();
1705 int res = fhandler_termios::ioctl (cmd, arg);
1706 if (res <= 0)
1707 return res;
1708
1709 if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid
1710 && (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ())
1711 && (get_ttyp ()->ti.c_lflag & TOSTOP))
1712 {
1713 /* background process */
1714 termios_printf ("bg ioctl pgid %d, tpgid %d, %s", myself->pgid,
1715 get_ttyp ()->getpgid (), myctty ());
1716 raise (SIGTTOU);
1717 }
1718
1719 int retval;
1720 switch (cmd)
1721 {
1722 case TIOCGWINSZ:
1723 case TIOCSWINSZ:
1724 break;
1725 case TIOCGPGRP:
1726 {
1727 pid_t pid = this->tcgetpgrp ();
1728 if (pid < 0)
1729 retval = -1;
1730 else
1731 {
1732 *((pid_t *) arg) = pid;
1733 retval = 0;
1734 }
1735 }
1736 goto out;
1737 case TIOCSPGRP:
1738 retval = this->tcsetpgrp ((pid_t) (intptr_t) arg);
1739 goto out;
1740 case FIONREAD:
1741 {
1742 DWORD n;
1743 if (!bytes_available (n))
1744 {
1745 set_errno (EINVAL);
1746 retval = -1;
1747 }
1748 else
1749 {
1750 *(int *) arg = (int) n;
1751 retval = 0;
1752 }
1753 }
1754 goto out;
1755 default:
1756 return fhandler_base::ioctl (cmd, arg);
1757 }
1758
1759 acquire_output_mutex (mutex_timeout);
1760
1761 get_ttyp ()->cmd = cmd;
1762 get_ttyp ()->ioctl_retval = 0;
1763 switch (cmd)
1764 {
1765 case TIOCGWINSZ:
1766 get_ttyp ()->arg.winsize = get_ttyp ()->winsize;
1767 *(struct winsize *) arg = get_ttyp ()->arg.winsize;
1768 get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
1769 break;
1770 case TIOCSWINSZ:
1771 if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
1772 || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col
1773 || get_ttyp ()->winsize.ws_ypixel != ((struct winsize *) arg)->ws_ypixel
1774 || get_ttyp ()->winsize.ws_xpixel != ((struct winsize *) arg)->ws_xpixel
1775 )
1776 {
1777 if (get_ttyp ()->pcon_activated && get_ttyp ()->pcon_pid)
1778 resize_pseudo_console ((struct winsize *) arg);
1779 get_ttyp ()->arg.winsize = *(struct winsize *) arg;
1780 get_ttyp ()->winsize = *(struct winsize *) arg;
1781 get_ttyp ()->kill_pgrp (SIGWINCH);
1782 }
1783 break;
1784 }
1785
1786 release_output_mutex ();
1787 retval = get_ttyp ()->ioctl_retval;
1788 if (retval < 0)
1789 {
1790 set_errno (-retval);
1791 retval = -1;
1792 }
1793
1794 out:
1795 termios_printf ("%d = ioctl(%x)", retval, cmd);
1796 return retval;
1797 }
1798
1799 int __reg2
1800 fhandler_pty_slave::fstat (struct stat *st)
1801 {
1802 fhandler_base::fstat (st);
1803
1804 bool to_close = false;
1805 if (!input_available_event)
1806 {
1807 char buf[MAX_PATH];
1808 shared_name (buf, INPUT_AVAILABLE_EVENT, get_minor ());
1809 input_available_event = OpenEvent (READ_CONTROL, TRUE, buf);
1810 if (input_available_event)
1811 to_close = true;
1812 }
1813 st->st_mode = S_IFCHR;
1814 if (!input_available_event
1815 || get_object_attribute (input_available_event, &st->st_uid, &st->st_gid,
1816 &st->st_mode))
1817 {
1818 /* If we can't access the ACL, or if the tty doesn't actually exist,
1819 then fake uid and gid to strict, system-like values. */
1820 st->st_mode = S_IFCHR | S_IRUSR | S_IWUSR;
1821 st->st_uid = 18;
1822 st->st_gid = 544;
1823 }
1824 if (to_close)
1825 CloseHandle (input_available_event);
1826 return 0;
1827 }
1828
1829 int __reg3
1830 fhandler_pty_slave::facl (int cmd, int nentries, aclent_t *aclbufp)
1831 {
1832 int res = -1;
1833 bool to_close = false;
1834 security_descriptor sd;
1835 mode_t attr = S_IFCHR;
1836
1837 switch (cmd)
1838 {
1839 case SETACL:
1840 if (!aclsort32 (nentries, 0, aclbufp))
1841 set_errno (ENOTSUP);
1842 break;
1843 case GETACL:
1844 if (!aclbufp)
1845 {
1846 set_errno (EFAULT);
1847 break;
1848 }
1849 fallthrough;
1850 case GETACLCNT:
1851 if (!input_available_event)
1852 {
1853 char buf[MAX_PATH];
1854 shared_name (buf, INPUT_AVAILABLE_EVENT, get_minor ());
1855 input_available_event = OpenEvent (READ_CONTROL, TRUE, buf);
1856 if (input_available_event)
1857 to_close = true;
1858 }
1859 if (!input_available_event
1860 || get_object_sd (input_available_event, sd))
1861 {
1862 res = get_posix_access (NULL, &attr, NULL, NULL, aclbufp, nentries);
1863 if (aclbufp && res == MIN_ACL_ENTRIES)
1864 {
1865 aclbufp[0].a_perm = S_IROTH | S_IWOTH;
1866 aclbufp[0].a_id = 18;
1867 aclbufp[1].a_id = 544;
1868 }
1869 break;
1870 }
1871 if (cmd == GETACL)
1872 res = get_posix_access (sd, &attr, NULL, NULL, aclbufp, nentries);
1873 else
1874 res = get_posix_access (sd, &attr, NULL, NULL, NULL, 0);
1875 break;
1876 default:
1877 set_errno (EINVAL);
1878 break;
1879 }
1880 if (to_close)
1881 CloseHandle (input_available_event);
1882 return res;
1883 }
1884
1885 /* Helper function for fchmod and fchown, which just opens all handles
1886 and signals success via bool return. */
1887 bool
1888 fhandler_pty_slave::fch_open_handles (bool chown)
1889 {
1890 char buf[MAX_PATH];
1891 DWORD write_access = WRITE_DAC | (chown ? WRITE_OWNER : 0);
1892
1893 _tc = cygwin_shared->tty[get_minor ()];
1894 shared_name (buf, INPUT_AVAILABLE_EVENT, get_minor ());
1895 input_available_event = OpenEvent (READ_CONTROL | write_access,
1896 TRUE, buf);
1897 output_mutex = get_ttyp ()->open_output_mutex (write_access);
1898 input_mutex = get_ttyp ()->open_input_mutex (write_access);
1899 pcon_mutex = get_ttyp ()->open_mutex (PCON_MUTEX, write_access);
1900 inuse = get_ttyp ()->open_inuse (write_access);
1901 if (!input_available_event || !output_mutex || !input_mutex || !inuse)
1902 {
1903 __seterrno ();
1904 return false;
1905 }
1906 return true;
1907 }
1908
1909 /* Helper function for fchmod and fchown, which sets the new security
1910 descriptor on all objects representing the pty. */
1911 int
1912 fhandler_pty_slave::fch_set_sd (security_descriptor &sd, bool chown)
1913 {
1914 security_descriptor sd_old;
1915
1916 get_object_sd (input_available_event, sd_old);
1917 if (!set_object_sd (input_available_event, sd, chown)
1918 && !set_object_sd (output_mutex, sd, chown)
1919 && !set_object_sd (input_mutex, sd, chown)
1920 && !set_object_sd (inuse, sd, chown))
1921 return 0;
1922 set_object_sd (input_available_event, sd_old, chown);
1923 set_object_sd (output_mutex, sd_old, chown);
1924 set_object_sd (input_mutex, sd_old, chown);
1925 set_object_sd (inuse, sd_old, chown);
1926 return -1;
1927 }
1928
1929 /* Helper function for fchmod and fchown, which closes all object handles in
1930 the pty. */
1931 void
1932 fhandler_pty_slave::fch_close_handles ()
1933 {
1934 close_maybe (input_available_event);
1935 close_maybe (output_mutex);
1936 close_maybe (input_mutex);
1937 close_maybe (inuse);
1938 }
1939
1940 int __reg1
1941 fhandler_pty_slave::fchmod (mode_t mode)
1942 {
1943 int ret = -1;
1944 bool to_close = false;
1945 security_descriptor sd;
1946 uid_t uid;
1947 gid_t gid;
1948 mode_t orig_mode = S_IFCHR;
1949
1950 if (!input_available_event)
1951 {
1952 to_close = true;
1953 if (!fch_open_handles (false))
1954 goto errout;
1955 }
1956 sd.malloc (sizeof (SECURITY_DESCRIPTOR));
1957 RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
1958 if (!get_object_attribute (input_available_event, &uid, &gid, &orig_mode)
1959 && !create_object_sd_from_attribute (uid, gid, S_IFCHR | mode, sd))
1960 ret = fch_set_sd (sd, false);
1961 errout:
1962 if (to_close)
1963 fch_close_handles ();
1964 return ret;
1965 }
1966
1967 int __reg2
1968 fhandler_pty_slave::fchown (uid_t uid, gid_t gid)
1969 {
1970 int ret = -1;
1971 bool to_close = false;
1972 security_descriptor sd;
1973 uid_t o_uid;
1974 gid_t o_gid;
1975 mode_t mode = S_IFCHR;
1976
1977 if (uid == ILLEGAL_UID && gid == ILLEGAL_GID)
1978 return 0;
1979 if (!input_available_event)
1980 {
1981 to_close = true;
1982 if (!fch_open_handles (true))
1983 goto errout;
1984 }
1985 sd.malloc (sizeof (SECURITY_DESCRIPTOR));
1986 RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
1987 if (!get_object_attribute (input_available_event, &o_uid, &o_gid, &mode))
1988 {
1989 if (uid == ILLEGAL_UID)
1990 uid = o_uid;
1991 if (gid == ILLEGAL_GID)
1992 gid = o_gid;
1993 if (uid == o_uid && gid == o_gid)
1994 ret = 0;
1995 else if (!create_object_sd_from_attribute (uid, gid, mode, sd))
1996 ret = fch_set_sd (sd, true);
1997 }
1998 errout:
1999 if (to_close)
2000 fch_close_handles ();
2001 return ret;
2002 }
2003
2004 /*******************************************************
2005 fhandler_pty_master
2006 */
2007 fhandler_pty_master::fhandler_pty_master (int unit)
2008 : fhandler_pty_common (), pktmode (0), master_ctl (NULL),
2009 master_thread (NULL), from_master_nat (NULL), to_master_nat (NULL),
2010 from_slave_nat (NULL), to_slave_nat (NULL), echo_r (NULL), echo_w (NULL),
2011 dwProcessId (0), to_master (NULL), from_master (NULL),
2012 master_fwd_thread (NULL)
2013 {
2014 if (unit >= 0)
2015 dev ().parse (DEV_PTYM_MAJOR, unit);
2016 set_name ("/dev/ptmx");
2017 }
2018
2019 int
2020 fhandler_pty_master::open (int flags, mode_t)
2021 {
2022 if (!setup ())
2023 return 0;
2024 set_open_status ();
2025 dwProcessId = GetCurrentProcessId ();
2026 return 1;
2027 }
2028
2029 bool
2030 fhandler_pty_master::open_setup (int flags)
2031 {
2032 set_flags ((flags & ~O_TEXT) | O_BINARY);
2033 char buf[sizeof ("opened pty master for ptyNNNNNNNNNNN")];
2034 __small_sprintf (buf, "opened pty master for pty%d", get_minor ());
2035 report_tty_counts (this, buf, "");
2036 return fhandler_base::open_setup (flags);
2037 }
2038
2039 off_t
2040 fhandler_pty_common::lseek (off_t, int)
2041 {
2042 set_errno (ESPIPE);
2043 return -1;
2044 }
2045
2046 int
2047 fhandler_pty_common::close ()
2048 {
2049 termios_printf ("pty%d <%p,%p> closing",
2050 get_minor (), get_handle (), get_output_handle ());
2051 if (!ForceCloseHandle (input_mutex))
2052 termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex);
2053 if (!ForceCloseHandle (pcon_mutex))
2054 termios_printf ("CloseHandle (pcon_mutex<%p>), %E", pcon_mutex);
2055 if (!ForceCloseHandle1 (get_handle (), from_pty))
2056 termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ());
2057 if (!ForceCloseHandle1 (get_output_handle (), to_pty))
2058 termios_printf ("CloseHandle (get_output_handle ()<%p>), %E",
2059 get_output_handle ());
2060
2061 return 0;
2062 }
2063
2064 void
2065 fhandler_pty_common::resize_pseudo_console (struct winsize *ws)
2066 {
2067 COORD size;
2068 size.X = ws->ws_col;
2069 size.Y = ws->ws_row;
2070 HPCON_INTERNAL hpcon_local;
2071 HANDLE pcon_owner =
2072 OpenProcess (PROCESS_DUP_HANDLE, FALSE, get_ttyp ()->pcon_pid);
2073 DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
2074 GetCurrentProcess (), &hpcon_local.hWritePipe,
2075 0, TRUE, DUPLICATE_SAME_ACCESS);
2076 ResizePseudoConsole ((HPCON) &hpcon_local, size);
2077 CloseHandle (pcon_owner);
2078 CloseHandle (hpcon_local.hWritePipe);
2079 }
2080
2081 void
2082 fhandler_pty_master::cleanup ()
2083 {
2084 report_tty_counts (this, "closing master", "");
2085 if (archetype)
2086 from_master_nat = from_master =
2087 to_master_nat = to_master = from_slave_nat = to_slave_nat = NULL;
2088 fhandler_base::cleanup ();
2089 }
2090
2091 int
2092 fhandler_pty_master::close ()
2093 {
2094 OBJECT_BASIC_INFORMATION obi;
2095 NTSTATUS status;
2096
2097 termios_printf ("closing from_master_nat(%p)/from_master(%p)/to_master_nat(%p)/to_master(%p) since we own them(%u)",
2098 from_master_nat, from_master,
2099 to_master_nat, to_master, dwProcessId);
2100 if (cygwin_finished_initializing)
2101 {
2102 if (master_ctl && get_ttyp ()->master_pid == myself->pid)
2103 {
2104 char buf[MAX_PATH];
2105 pipe_request req = { (DWORD) -1 };
2106 pipe_reply repl;
2107 DWORD len;
2108
2109 __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
2110 &cygheap->installation_key, get_minor ());
2111 acquire_output_mutex (mutex_timeout);
2112 if (master_ctl)
2113 {
2114 CallNamedPipe (buf, &req, sizeof req, &repl, sizeof repl, &len,
2115 500);
2116 CloseHandle (master_ctl);
2117 master_thread->detach ();
2118 get_ttyp ()->set_master_ctl_closed ();
2119 master_ctl = NULL;
2120 }
2121 release_output_mutex ();
2122 get_ttyp ()->stop_fwd_thread = true;
2123 WriteFile (to_master_nat, "", 0, NULL, NULL);
2124 master_fwd_thread->detach ();
2125 }
2126 }
2127
2128 /* Check if the last master handle has been closed. If so, set
2129 input_available_event to wake up potentially waiting slaves. */
2130 acquire_output_mutex (mutex_timeout);
2131 status = NtQueryObject (get_output_handle (), ObjectBasicInformation,
2132 &obi, sizeof obi, NULL);
2133 fhandler_pty_common::close ();
2134 release_output_mutex ();
2135 if (!ForceCloseHandle (output_mutex))
2136 termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
2137 if (!NT_SUCCESS (status))
2138 debug_printf ("NtQueryObject: %y", status);
2139 else if (obi.HandleCount == 1)
2140 {
2141 termios_printf ("Closing last master of pty%d", get_minor ());
2142 if (get_ttyp ()->getsid () > 0)
2143 kill (get_ttyp ()->getsid (), SIGHUP);
2144 SetEvent (input_available_event);
2145 }
2146
2147 if (!ForceCloseHandle (from_master_nat))
2148 termios_printf ("error closing from_master_nat %p, %E", from_master_nat);
2149 if (!ForceCloseHandle (to_master_nat))
2150 termios_printf ("error closing to_master_nat %p, %E", to_master_nat);
2151 from_master_nat = to_master_nat = NULL;
2152 if (!ForceCloseHandle (from_slave_nat))
2153 termios_printf ("error closing from_slave_nat %p, %E", from_slave_nat);
2154 from_slave_nat = NULL;
2155 if (!ForceCloseHandle (to_master))
2156 termios_printf ("error closing to_master %p, %E", to_master);
2157 to_master = NULL;
2158 ForceCloseHandle (echo_r);
2159 ForceCloseHandle (echo_w);
2160 echo_r = echo_w = NULL;
2161 if (to_slave_nat)
2162 ForceCloseHandle (to_slave_nat);
2163 to_slave_nat = NULL;
2164
2165 if (have_execed || get_ttyp ()->master_pid != myself->pid)
2166 termios_printf ("not clearing: %d, master_pid %d",
2167 have_execed, get_ttyp ()->master_pid);
2168 if (!ForceCloseHandle (input_available_event))
2169 termios_printf ("CloseHandle (input_available_event<%p>), %E",
2170 input_available_event);
2171
2172 /* The from_master must be closed last so that the same pty is not
2173 allocated before cleaning up the other corresponding instances. */
2174 if (!ForceCloseHandle (from_master))
2175 termios_printf ("error closing from_master %p, %E", from_master);
2176 from_master = NULL;
2177
2178 return 0;
2179 }
2180
2181 ssize_t __stdcall
2182 fhandler_pty_master::write (const void *ptr, size_t len)
2183 {
2184 ssize_t ret;
2185 char *p = (char *) ptr;
2186 termios &ti = tc ()->ti;
2187
2188 bg_check_types bg = bg_check (SIGTTOU);
2189 if (bg <= bg_eof)
2190 return (ssize_t) bg;
2191
2192 push_process_state process_state (PID_TTYOU);
2193
2194 if (get_ttyp ()->pcon_start)
2195 {
2196 /* Pseudo condole support uses "CSI6n" to get cursor position.
2197 If the reply for "CSI6n" is divided into multiple writes,
2198 pseudo console sometimes does not recognize it. Therefore,
2199 put them together into wpbuf and write all at once. */
2200 static const int wpbuf_len = strlen ("\033[32768;32868R");
2201 static char wpbuf[wpbuf_len];
2202 static int ixput = 0;
2203 static int state = 0;
2204
2205 DWORD n;
2206 WaitForSingleObject (input_mutex, mutex_timeout);
2207 for (size_t i = 0; i < len; i++)
2208 {
2209 if (p[i] == '\033')
2210 {
2211 if (ixput)
2212 line_edit (wpbuf, ixput, ti, &ret);
2213 ixput = 0;
2214 state = 1;
2215 }
2216 if (state == 1)
2217 {
2218 if (ixput < wpbuf_len)
2219 wpbuf[ixput++] = p[i];
2220 else
2221 {
2222 if (!get_ttyp ()->req_xfer_input)
2223 WriteFile (to_slave_nat, wpbuf, ixput, &n, NULL);
2224 ixput = 0;
2225 wpbuf[ixput++] = p[i];
2226 }
2227 }
2228 else
2229 line_edit (p + i, 1, ti, &ret);
2230 if (state == 1 && p[i] == 'R')
2231 state = 2;
2232 }
2233 if (state == 2)
2234 {
2235 if (!get_ttyp ()->req_xfer_input)
2236 WriteFile (to_slave_nat, wpbuf, ixput, &n, NULL);
2237 ixput = 0;
2238 state = 0;
2239 get_ttyp ()->req_xfer_input = false;
2240 get_ttyp ()->pcon_start = false;
2241 }
2242 ReleaseMutex (input_mutex);
2243
2244 if (!get_ttyp ()->pcon_start)
2245 {
2246 pinfo pp (get_ttyp ()->pcon_start_pid);
2247 bool pcon_fg = (pp && get_ttyp ()->getpgid () == pp->pgid);
2248 /* GDB may set WINPID rather than cygwin PID to process group
2249 when the debugged process is a non-cygwin process.*/
2250 pcon_fg |= !pinfo (get_ttyp ()->getpgid ());
2251 if (get_ttyp ()->switch_to_pcon_in && pcon_fg
2252 && get_ttyp ()->pcon_input_state_eq (tty::to_cyg))
2253 {
2254 /* This accept_input() call is needed in order to transfer input
2255 which is not accepted yet to non-cygwin pipe. */
2256 if (get_readahead_valid ())
2257 accept_input ();
2258 WaitForSingleObject (input_mutex, mutex_timeout);
2259 fhandler_pty_slave::transfer_input (tty::to_nat, from_master,
2260 get_ttyp (),
2261 input_available_event);
2262 ReleaseMutex (input_mutex);
2263 }
2264 get_ttyp ()->pcon_start_pid = 0;
2265 }
2266
2267 return len;
2268 }
2269
2270 /* Write terminal input to to_slave_nat pipe instead of output_handle
2271 if current application is native console application. */
2272 WaitForSingleObject (input_mutex, mutex_timeout);
2273 if (to_be_read_from_pcon () && get_ttyp ()->pcon_activated
2274 && get_ttyp ()->pcon_input_state == tty::to_nat)
2275 {
2276 tmp_pathbuf tp;
2277 char *buf = (char *) ptr;
2278 size_t nlen = len;
2279 if (get_ttyp ()->term_code_page != CP_UTF8)
2280 {
2281 static mbstate_t mbp;
2282 buf = tp.c_get ();
2283 nlen = NT_MAX_PATH;
2284 convert_mb_str (CP_UTF8, buf, &nlen,
2285 get_ttyp ()->term_code_page, (const char *) ptr, len,
2286 &mbp);
2287 }
2288
2289 if ((ti.c_lflag & ISIG) && memchr (buf, '\003', nlen))
2290 {
2291 /* If the process is started with CREATE_NEW_PROCESS_GROUP
2292 flag, Ctrl-C will not be sent to that process. Therefore,
2293 send Ctrl-break event to that process here. */
2294 DWORD wpid = 0;
2295 winpids pids ((DWORD) 0);
2296 for (unsigned i = 0; i < pids.npids; i++)
2297 {
2298 _pinfo *p = pids[i];
2299 if (p->ctty == get_ttyp ()->ntty
2300 && p->pgid == get_ttyp ()->getpgid ()
2301 && (p->process_state & PID_NOTCYGWIN)
2302 && (p->process_state & PID_NEW_PG))
2303 {
2304 wpid = p->dwProcessId;
2305 break;
2306 }
2307 }
2308 pinfo pinfo_resume = pinfo (myself->ppid);
2309 DWORD resume_pid;
2310 if (pinfo_resume)
2311 resume_pid = pinfo_resume->dwProcessId;
2312 else
2313 resume_pid = get_console_process_id (myself->dwProcessId, false);
2314 if (wpid && resume_pid)
2315 {
2316 WaitForSingleObject (pcon_mutex, INFINITE);
2317 FreeConsole ();
2318 AttachConsole (wpid);
2319 /* CTRL_C_EVENT does not work for the process started with
2320 CREATE_NEW_PROCESS_GROUP flag, so send CTRL_BREAK_EVENT
2321 instead. */
2322 GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, wpid);
2323 FreeConsole ();
2324 AttachConsole (resume_pid);
2325 ReleaseMutex (pcon_mutex);
2326 }
2327 if (!(ti.c_lflag & NOFLSH))
2328 get_ttyp ()->discard_input = true;
2329 }
2330 DWORD n;
2331 WriteFile (to_slave_nat, buf, nlen, &n, NULL);
2332 ReleaseMutex (input_mutex);
2333
2334 return len;
2335 }
2336
2337 /* This input transfer is needed when cygwin-app which is started from
2338 non-cygwin app is terminated if pseudo console is disabled. */
2339 if (to_be_read_from_pcon () && !get_ttyp ()->pcon_activated
2340 && get_ttyp ()->pcon_input_state == tty::to_cyg)
2341 fhandler_pty_slave::transfer_input (tty::to_nat, from_master,
2342 get_ttyp (), input_available_event);
2343 ReleaseMutex (input_mutex);
2344
2345 line_edit_status status = line_edit (p, len, ti, &ret);
2346 if (status > line_edit_signalled && status != line_edit_pipe_full)
2347 ret = -1;
2348 return ret;
2349 }
2350
2351 void __reg3
2352 fhandler_pty_master::read (void *ptr, size_t& len)
2353 {
2354 bg_check_types bg = bg_check (SIGTTIN);
2355 if (bg <= bg_eof)
2356 {
2357 len = (size_t) bg;
2358 return;
2359 }
2360 push_process_state process_state (PID_TTYIN);
2361 len = (size_t) process_slave_output ((char *) ptr, len, pktmode);
2362 }
2363
2364 int
2365 fhandler_pty_master::tcgetattr (struct termios *t)
2366 {
2367 *t = cygwin_shared->tty[get_minor ()]->ti;
2368 /* Workaround for rlwrap v0.40 or later */
2369 if (get_ttyp ()->pcon_start)
2370 t->c_lflag &= ~(ICANON | ECHO);
2371 if (get_ttyp ()->pcon_activated)
2372 t->c_iflag &= ~ICRNL;
2373 return 0;
2374 }
2375
2376 int
2377 fhandler_pty_master::tcsetattr (int, const struct termios *t)
2378 {
2379 cygwin_shared->tty[get_minor ()]->ti = *t;
2380 return 0;
2381 }
2382
2383 int
2384 fhandler_pty_master::tcflush (int queue)
2385 {
2386 int ret = 0;
2387
2388 termios_printf ("tcflush(%d) handle %p", queue, get_handle ());
2389
2390 if (queue == TCIFLUSH || queue == TCIOFLUSH)
2391 ret = process_slave_output (NULL, OUT_BUFFER_SIZE, 0);
2392 if (queue == TCOFLUSH || queue == TCIOFLUSH)
2393 {
2394 /* do nothing for now. */
2395 }
2396
2397 termios_printf ("%d=tcflush(%d)", ret, queue);
2398 return ret;
2399 }
2400
2401 int
2402 fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
2403 {
2404 int res = fhandler_termios::ioctl (cmd, arg);
2405 if (res <= 0)
2406 return res;
2407
2408 switch (cmd)
2409 {
2410 case TIOCPKT:
2411 pktmode = *(int *) arg;
2412 break;
2413 case TIOCGWINSZ:
2414 *(struct winsize *) arg = get_ttyp ()->winsize;
2415 break;
2416 case TIOCSWINSZ:
2417 if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
2418 || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col
2419 || get_ttyp ()->winsize.ws_ypixel != ((struct winsize *) arg)->ws_ypixel
2420 || get_ttyp ()->winsize.ws_xpixel != ((struct winsize *) arg)->ws_xpixel
2421 )
2422 {
2423 if (get_ttyp ()->pcon_activated && get_ttyp ()->pcon_pid)
2424 resize_pseudo_console ((struct winsize *) arg);
2425 get_ttyp ()->winsize = *(struct winsize *) arg;
2426 get_ttyp ()->kill_pgrp (SIGWINCH);
2427 }
2428 break;
2429 case TIOCGPGRP:
2430 *((pid_t *) arg) = this->tcgetpgrp ();
2431 break;
2432 case TIOCSPGRP:
2433 return this->tcsetpgrp ((pid_t) (intptr_t) arg);
2434 case FIONREAD:
2435 {
2436 DWORD n;
2437 if (!bytes_available (n))
2438 {
2439 set_errno (EINVAL);
2440 return -1;
2441 }
2442 *(int *) arg = (int) n;
2443 }
2444 break;
2445 default:
2446 return fhandler_base::ioctl (cmd, arg);
2447 }
2448 return 0;
2449 }
2450
2451 int
2452 fhandler_pty_master::ptsname_r (char *buf, size_t buflen)
2453 {
2454 char tmpbuf[TTY_NAME_MAX];
2455
2456 __ptsname (tmpbuf, get_minor ());
2457 if (buflen <= strlen (tmpbuf))
2458 {
2459 set_errno (ERANGE);
2460 return ERANGE;
2461 }
2462 strcpy (buf, tmpbuf);
2463 return 0;
2464 }
2465
2466 void
2467 fhandler_pty_common::set_close_on_exec (bool val)
2468 {
2469 // Cygwin processes will handle this specially on exec.
2470 close_on_exec (val);
2471 }
2472
2473 void
2474 fhandler_pty_slave::setup_locale (void)
2475 {
2476 extern UINT __eval_codepage_from_internal_charset ();
2477
2478 if (!get_ttyp ()->term_code_page)
2479 {
2480 get_ttyp ()->term_code_page = __eval_codepage_from_internal_charset ();
2481 SetConsoleCP (get_ttyp ()->term_code_page);
2482 SetConsoleOutputCP (get_ttyp ()->term_code_page);
2483 }
2484 }
2485
2486 void
2487 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
2488 {
2489 // fork_fixup (parent, inuse, "inuse");
2490 // fhandler_pty_common::fixup_after_fork (parent);
2491 report_tty_counts (this, "inherited", "");
2492 }
2493
2494 void
2495 fhandler_pty_slave::fixup_after_exec ()
2496 {
2497 reset_switch_to_pcon ();
2498 create_invisible_console ();
2499
2500 if (!close_on_exec ())
2501 fixup_after_fork (NULL); /* No parent handle required. */
2502
2503 /* Hook Console API */
2504 #define DO_HOOK(module, name) \
2505 if (!name##_Orig) \
2506 { \
2507 void *api = hook_api (module, #name, (void *) name##_Hooked); \
2508 name##_Orig = (__typeof__ (name) *) api; \
2509 /*if (api) system_printf (#name " hooked.");*/ \
2510 }
2511 /* CreateProcess() is hooked for GDB etc. */
2512 DO_HOOK (NULL, CreateProcessA);
2513 DO_HOOK (NULL, CreateProcessW);
2514 }
2515
2516 /* This thread function handles the master control pipe. It waits for a
2517 client to connect. Then it checks if the client process has permissions
2518 to access the tty handles. If so, it opens the client process and
2519 duplicates the handles into that process. If that fails, it sends a reply
2520 with at least one handle set to NULL and an error code. Last but not
2521 least, the client is disconnected and the thread waits for the next client.
2522
2523 A special case is when the master side of the tty is about to be closed.
2524 The client side is the fhandler_pty_master::close function and it sends
2525 a PID -1 in that case. A check is performed that the request to leave
2526 really comes from the master process itself.
2527
2528 Since there's always only one pipe instance, there's a chance that clients
2529 have to wait to connect to the master control pipe. Therefore the client
2530 calls to CallNamedPipe should have a big enough timeout value. For now this
2531 is 500ms. Hope that's enough. */
2532
2533 /* The function pty_master_thread() should be static because the instance
2534 is deleted if the master is dup()'ed and the original is closed. In
2535 this case, dup()'ed instance still exists, therefore, master thread
2536 is also still alive even though the instance has been deleted. As a
2537 result, accesing member variables in this function causes access
2538 violation. */
2539
2540 DWORD
2541 fhandler_pty_master::pty_master_thread (const master_thread_param_t *p)
2542 {
2543 bool exit = false;
2544 GENERIC_MAPPING map = { EVENT_QUERY_STATE, EVENT_MODIFY_STATE, 0,
2545 EVENT_QUERY_STATE | EVENT_MODIFY_STATE };
2546 pipe_request req;
2547 DWORD len;
2548 security_descriptor sd;
2549 HANDLE token;
2550 PRIVILEGE_SET ps;
2551 DWORD pid;
2552 NTSTATUS status;
2553
2554 termios_printf ("Entered");
2555 while (!exit && (ConnectNamedPipe (p->master_ctl, NULL)
2556 || GetLastError () == ERROR_PIPE_CONNECTED))
2557 {
2558 pipe_reply repl = { NULL, NULL, NULL, NULL, NULL, NULL, 0 };
2559 bool deimp = false;
2560 NTSTATUS allow = STATUS_ACCESS_DENIED;
2561 ACCESS_MASK access = EVENT_MODIFY_STATE;
2562 HANDLE client = NULL;
2563
2564 if (!ReadFile (p->master_ctl, &req, sizeof req, &len, NULL))
2565 {
2566 termios_printf ("ReadFile, %E");
2567 goto reply;
2568 }
2569 if (!GetNamedPipeClientProcessId (p->master_ctl, &pid))
2570 pid = req.pid;
2571 if (get_object_sd (p->input_available_event, sd))
2572 {
2573 termios_printf ("get_object_sd, %E");
2574 goto reply;
2575 }
2576 cygheap->user.deimpersonate ();
2577 deimp = true;
2578 if (!ImpersonateNamedPipeClient (p->master_ctl))
2579 {
2580 termios_printf ("ImpersonateNamedPipeClient, %E");
2581 goto reply;
2582 }
2583 status = NtOpenThreadToken (GetCurrentThread (), TOKEN_QUERY, TRUE,
2584 &token);
2585 if (!NT_SUCCESS (status))
2586 {
2587 termios_printf ("NtOpenThreadToken, %y", status);
2588 SetLastError (RtlNtStatusToDosError (status));
2589 goto reply;
2590 }
2591 len = sizeof ps;
2592 status = NtAccessCheck (sd, token, access, &map, &ps, &len, &access,
2593 &allow);
2594 NtClose (token);
2595 if (!NT_SUCCESS (status))
2596 {
2597 termios_printf ("NtAccessCheck, %y", status);
2598 SetLastError (RtlNtStatusToDosError (status));
2599 goto reply;
2600 }
2601 if (!RevertToSelf ())
2602 {
2603 termios_printf ("RevertToSelf, %E");
2604 goto reply;
2605 }
2606 if (req.pid == (DWORD) -1) /* Request to finish thread. */
2607 {
2608 /* Check if the requesting process is the master process itself. */
2609 if (pid == GetCurrentProcessId ())
2610 exit = true;
2611 goto reply;
2612 }
2613 if (NT_SUCCESS (allow))
2614 {
2615 client = OpenProcess (PROCESS_DUP_HANDLE, FALSE, pid);
2616 if (!client)
2617 {
2618 termios_printf ("OpenProcess, %E");
2619 goto reply;
2620 }
2621 if (!DuplicateHandle (GetCurrentProcess (), p->from_master_nat,
2622 client, &repl.from_master_nat,
2623 0, TRUE, DUPLICATE_SAME_ACCESS))
2624 {
2625 termios_printf ("DuplicateHandle (from_master_nat), %E");
2626 goto reply;
2627 }
2628 if (!DuplicateHandle (GetCurrentProcess (), p->from_master,
2629 client, &repl.from_master,
2630 0, TRUE, DUPLICATE_SAME_ACCESS))
2631 {
2632 termios_printf ("DuplicateHandle (from_master), %E");
2633 goto reply;
2634 }
2635 if (!DuplicateHandle (GetCurrentProcess (), p->to_master_nat,
2636 client, &repl.to_master_nat,
2637 0, TRUE, DUPLICATE_SAME_ACCESS))
2638 {
2639 termios_printf ("DuplicateHandle (to_master_nat), %E");
2640 goto reply;
2641 }
2642 if (!DuplicateHandle (GetCurrentProcess (), p->to_master,
2643 client, &repl.to_master,
2644 0, TRUE, DUPLICATE_SAME_ACCESS))
2645 {
2646 termios_printf ("DuplicateHandle (to_master), %E");
2647 goto reply;
2648 }
2649 if (!DuplicateHandle (GetCurrentProcess (), p->to_slave_nat,
2650 client, &repl.to_slave_nat,
2651 0, TRUE, DUPLICATE_SAME_ACCESS))
2652 {
2653 termios_printf ("DuplicateHandle (to_slave_nat), %E");
2654 goto reply;
2655 }
2656 if (!DuplicateHandle (GetCurrentProcess (), p->to_slave,
2657 client, &repl.to_slave,
2658 0, TRUE, DUPLICATE_SAME_ACCESS))
2659 {
2660 termios_printf ("DuplicateHandle (to_slave), %E");
2661 goto reply;
2662 }
2663 }
2664 reply:
2665 repl.error = GetLastError ();
2666 if (client)
2667 CloseHandle (client);
2668 if (deimp)
2669 cygheap->user.reimpersonate ();
2670 sd.free ();
2671 termios_printf ("Reply: from %p, to %p, error %u",
2672 repl.from_master_nat, repl.to_master_nat, repl.error );
2673 if (!WriteFile (p->master_ctl, &repl, sizeof repl, &len, NULL))
2674 termios_printf ("WriteFile, %E");
2675 if (!DisconnectNamedPipe (p->master_ctl))
2676 termios_printf ("DisconnectNamedPipe, %E");
2677 }
2678 termios_printf ("Leaving");
2679 return 0;
2680 }
2681
2682 static DWORD WINAPI
2683 pty_master_thread (VOID *arg)
2684 {
2685 fhandler_pty_master::master_thread_param_t p;
2686 ((fhandler_pty_master *) arg)->get_master_thread_param (&p);
2687 return fhandler_pty_master::pty_master_thread (&p);
2688 }
2689
2690 /* The function pty_master_fwd_thread() should be static because the
2691 instance is deleted if the master is dup()'ed and the original is
2692 closed. In this case, dup()'ed instance still exists, therefore,
2693 master forwarding thread is also still alive even though the instance
2694 has been deleted. As a result, accesing member variables in this
2695 function causes access violation. */
2696
2697 DWORD
2698 fhandler_pty_master::pty_master_fwd_thread (const master_fwd_thread_param_t *p)
2699 {
2700 DWORD rlen;
2701 tmp_pathbuf tp;
2702 char *outbuf = tp.c_get ();
2703 char *mbbuf = tp.c_get ();
2704 static mbstate_t mbp;
2705
2706 termios_printf ("Started.");
2707 for (;;)
2708 {
2709 p->ttyp->pcon_last_time = GetTickCount ();
2710 if (!ReadFile (p->from_slave_nat, outbuf, NT_MAX_PATH, &rlen, NULL))
2711 {
2712 termios_printf ("ReadFile for forwarding failed, %E");
2713 break;
2714 }
2715 if (p->ttyp->stop_fwd_thread)
2716 break;
2717 ssize_t wlen = rlen;
2718 char *ptr = outbuf;
2719 if (p->ttyp->pcon_activated)
2720 {
2721 /* Avoid setting window title to "cygwin-console-helper.exe" */
2722 int state = 0;
2723 int start_at = 0;
2724 for (DWORD i=0; i<rlen; i++)
2725 if (outbuf[i] == '\033')
2726 {
2727 start_at = i;
2728 state = 1;
2729 continue;
2730 }
2731 else if ((state == 1 && outbuf[i] == ']') ||
2732 (state == 2 && outbuf[i] == '0') ||
2733 (state == 3 && outbuf[i] == ';'))
2734 {
2735 state ++;
2736 continue;
2737 }
2738 else if (state == 4 && outbuf[i] == '\a')
2739 {
2740 const char *helper_str = "\\bin\\cygwin-console-helper.exe";
2741 if (memmem (&outbuf[start_at], i + 1 - start_at,
2742 helper_str, strlen (helper_str)))
2743 {
2744 memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
2745 rlen = wlen = start_at + rlen - i - 1;
2746 }
2747 state = 0;
2748 continue;
2749 }
2750 else if (outbuf[i] == '\a')
2751 {
2752 state = 0;
2753 continue;
2754 }
2755
2756 /* Remove CSI > Pm m */
2757 state = 0;
2758 start_at = 0;
2759 for (DWORD i = 0; i < rlen; i++)
2760 if (outbuf[i] == '\033')
2761 {
2762 start_at = i;
2763 state = 1;
2764 continue;
2765 }
2766 else if ((state == 1 && outbuf[i] == '[')
2767 || (state == 2 && outbuf[i] == '>'))
2768 {
2769 state ++;
2770 continue;
2771 }
2772 else if (state == 3 && (isdigit (outbuf[i]) || outbuf[i] == ';'))
2773 continue;
2774 else if (state == 3 && outbuf[i] == 'm')
2775 {
2776 memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
2777 rlen = wlen = start_at + rlen - i - 1;
2778 state = 0;
2779 i = start_at - 1;
2780 continue;
2781 }
2782 else
2783 state = 0;
2784
2785 /* Remove OSC Ps ; ? BEL/ST */
2786 for (DWORD i = 0; i < rlen; i++)
2787 if (state == 0 && outbuf[i] == '\033')
2788 {
2789 start_at = i;
2790 state = 1;
2791 continue;
2792 }
2793 else if ((state == 1 && outbuf[i] == ']')
2794 || (state == 2 && outbuf[i] == ';')
2795 || (state == 3 && outbuf[i] == '?')
2796 || (state == 4 && outbuf[i] == '\033'))
2797 {
2798 state ++;
2799 continue;
2800 }
2801 else if (state == 2 && isdigit (outbuf[i]))
2802 continue;
2803 else if ((state == 4 && outbuf[i] == '\a')
2804 || (state == 5 && outbuf[i] == '\\'))
2805 {
2806 memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
2807 rlen = wlen = start_at + rlen - i - 1;
2808 state = 0;
2809 i = start_at - 1;
2810 continue;
2811 }
2812 else
2813 state = 0;
2814
2815 if (p->ttyp->term_code_page != CP_UTF8)
2816 {
2817 size_t nlen = NT_MAX_PATH;
2818 convert_mb_str (p->ttyp->term_code_page, mbbuf, &nlen,
2819 CP_UTF8, ptr, wlen, &mbp);
2820
2821 ptr = mbbuf;
2822 wlen = rlen = nlen;
2823 }
2824
2825 /* OPOST processing was already done in pseudo console,
2826 so just write it to to_master. */
2827 DWORD written;
2828 while (rlen>0)
2829 {
2830 if (!WriteFile (p->to_master, ptr, wlen, &written, NULL))
2831 {
2832 termios_printf ("WriteFile for forwarding failed, %E");
2833 break;
2834 }
2835 ptr += written;
2836 wlen = (rlen -= written);
2837 }
2838 continue;
2839 }
2840
2841 UINT cp_from;
2842 pinfo pinfo_target = pinfo (p->ttyp->invisible_console_pid);
2843 DWORD target_pid = 0;
2844 if (pinfo_target)
2845 target_pid = pinfo_target->dwProcessId;
2846 pinfo pinfo_resume = pinfo (myself->ppid);
2847 DWORD resume_pid;
2848 if (pinfo_resume)
2849 resume_pid = pinfo_resume->dwProcessId;
2850 else
2851 resume_pid = get_console_process_id (myself->dwProcessId, false);
2852 if (target_pid && resume_pid)
2853 {
2854 /* Slave attaches to a different console than master.
2855 Therefore reattach here. */
2856 acquire_attach_mutex (mutex_timeout);
2857 FreeConsole ();
2858 AttachConsole (target_pid);
2859 cp_from = GetConsoleOutputCP ();
2860 FreeConsole ();
2861 AttachConsole (resume_pid);
2862 release_attach_mutex ();
2863 }
2864 else
2865 cp_from = GetConsoleOutputCP ();
2866
2867 if (p->ttyp->term_code_page != cp_from)
2868 {
2869 size_t nlen = NT_MAX_PATH;
2870 convert_mb_str (p->ttyp->term_code_page, mbbuf, &nlen,
2871 cp_from, ptr, wlen, &mbp);
2872
2873 ptr = mbbuf;
2874 wlen = rlen = nlen;
2875 }
2876
2877 WaitForSingleObject (p->output_mutex, mutex_timeout);
2878 while (rlen>0)
2879 {
2880 if (!process_opost_output (p->to_master, ptr, wlen, false,
2881 p->ttyp, false))
2882 {
2883 termios_printf ("WriteFile for forwarding failed, %E");
2884 break;
2885 }
2886 ptr += wlen;
2887 wlen = (rlen -= wlen);
2888 }
2889 ReleaseMutex (p->output_mutex);
2890 }
2891 return 0;
2892 }
2893
2894 static DWORD WINAPI
2895 pty_master_fwd_thread (VOID *arg)
2896 {
2897 fhandler_pty_master::master_fwd_thread_param_t p;
2898 ((fhandler_pty_master *) arg)->get_master_fwd_thread_param (&p);
2899 return fhandler_pty_master::pty_master_fwd_thread (&p);
2900 }
2901
2902 inline static bool
2903 is_running_as_service (void)
2904 {
2905 return check_token_membership (well_known_service_sid)
2906 || cygheap->user.saved_sid () == well_known_system_sid;
2907 }
2908
2909 bool
2910 fhandler_pty_master::setup ()
2911 {
2912 int res;
2913 security_descriptor sd;
2914 SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE };
2915
2916 /* Find an unallocated pty to use. */
2917 int unit = cygwin_shared->tty.allocate (from_master, get_output_handle ());
2918 if (unit < 0)
2919 return false;
2920
2921 ProtectHandle1 (get_output_handle (), to_pty);
2922
2923 tty& t = *cygwin_shared->tty[unit];
2924 _tc = (tty_min *) &t;
2925
2926 tcinit (true); /* Set termios information. Force initialization. */
2927
2928 const char *errstr = NULL;
2929 DWORD pipe_mode = PIPE_NOWAIT;
2930
2931 if (!SetNamedPipeHandleState (get_output_handle (), &pipe_mode, NULL, NULL))
2932 termios_printf ("can't set output_handle(%p) to non-blocking mode",
2933 get_output_handle ());
2934
2935 char pipename[sizeof ("ptyNNNN-from-master-nat")];
2936 __small_sprintf (pipename, "pty%d-to-master-nat", unit);
2937 res = fhandler_pipe::create (&sec_none, &from_slave_nat, &to_master_nat,
2938 fhandler_pty_common::pipesize, pipename, 0);
2939 if (res)
2940 {
2941 errstr = "output pipe for non-cygwin apps";
2942 goto err;
2943 }
2944
2945 __small_sprintf (pipename, "pty%d-to-master", unit);
2946 res = fhandler_pipe::create (&sec_none, &get_handle (), &to_master,
2947 fhandler_pty_common::pipesize, pipename, 0);
2948 if (res)
2949 {
2950 errstr = "output pipe";
2951 goto err;
2952 }
2953
2954 __small_sprintf (pipename, "pty%d-from-master-nat", unit);
2955 /* FILE_FLAG_OVERLAPPED is specified here in order to prevent
2956 PeekNamedPipe() from blocking in transfer_input().
2957 Accordig to the official document, in order to access the handle
2958 opened with FILE_FLAG_OVERLAPPED, it is mandatory to pass the
2959 OVERLAPP structure, but in fact, it seems that the access will
2960 fallback to the blocking access if it is not specified. */
2961 res = fhandler_pipe::create (&sec_none, &from_master_nat, &to_slave_nat,
2962 fhandler_pty_common::pipesize, pipename,
2963 FILE_FLAG_OVERLAPPED);
2964 if (res)
2965 {
2966 errstr = "input pipe";
2967 goto err;
2968 }
2969
2970 ProtectHandle1 (get_handle (), from_pty);
2971
2972 __small_sprintf (pipename, "pty%d-echoloop", unit);
2973 res = fhandler_pipe::create (&sec_none, &echo_r, &echo_w,
2974 fhandler_pty_common::pipesize, pipename, 0);
2975 if (res)
2976 {
2977 errstr = "echo pipe";
2978 goto err;
2979 }
2980
2981 /* Create security attribute. Default permissions are 0620. */
2982 sd.malloc (sizeof (SECURITY_DESCRIPTOR));
2983 RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
2984 if (!create_object_sd_from_attribute (myself->uid, myself->gid,
2985 S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP,
2986 sd))
2987 sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) sd;
2988
2989 /* Carefully check that the input_available_event didn't already exist.
2990 This is a measure to make sure that the event security descriptor
2991 isn't occupied by a malicious process. We must make sure that the
2992 event's security descriptor is what we expect it to be. */
2993 if (!(input_available_event = t.get_event (errstr = INPUT_AVAILABLE_EVENT,
2994 &sa, TRUE))
2995 || GetLastError () == ERROR_ALREADY_EXISTS)
2996 goto err;
2997
2998 char buf[MAX_PATH];
2999 errstr = shared_name (buf, OUTPUT_MUTEX, unit);
3000 if (!(output_mutex = CreateMutex (&sa, FALSE, buf)))
3001 goto err;
3002
3003 errstr = shared_name (buf, INPUT_MUTEX, unit);
3004 if (!(input_mutex = CreateMutex (&sa, FALSE, buf)))
3005 goto err;
3006
3007 errstr = shared_name (buf, PCON_MUTEX, unit);
3008 if (!(pcon_mutex = CreateMutex (&sa, FALSE, buf)))
3009 goto err;
3010
3011 if (!attach_mutex)
3012 attach_mutex = CreateMutex (&sa, FALSE, NULL);
3013
3014 /* Create master control pipe which allows the master to duplicate
3015 the pty pipe handles to processes which deserve it. */
3016 __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
3017 &cygheap->installation_key, unit);
3018 master_ctl = CreateNamedPipe (buf, PIPE_ACCESS_DUPLEX
3019 | FILE_FLAG_FIRST_PIPE_INSTANCE,
3020 PIPE_WAIT | PIPE_TYPE_MESSAGE
3021 | PIPE_READMODE_MESSAGE
3022 | PIPE_REJECT_REMOTE_CLIENTS,
3023 1, 4096, 4096, 0, &sec_all_nih);
3024 if (master_ctl == INVALID_HANDLE_VALUE)
3025 {
3026 errstr = "pty master control pipe";
3027 goto err;
3028 }
3029
3030 thread_param_copied_event = CreateEvent(NULL, FALSE, FALSE, NULL);
3031 master_thread = new cygthread (::pty_master_thread, this, "ptym");
3032 if (!master_thread)
3033 {
3034 errstr = "pty master control thread";
3035 goto err;
3036 }
3037 WaitForSingleObject (thread_param_copied_event, INFINITE);
3038 master_fwd_thread = new cygthread (::pty_master_fwd_thread, this, "ptymf");
3039 if (!master_fwd_thread)
3040 {
3041 errstr = "pty master forwarding thread";
3042 goto err;
3043 }
3044 WaitForSingleObject (thread_param_copied_event, INFINITE);
3045 CloseHandle (thread_param_copied_event);
3046
3047 t.set_from_master_nat (from_master_nat);
3048 t.set_from_master (from_master);
3049 t.set_to_master_nat (to_master_nat);
3050 t.set_to_master (to_master);
3051 t.set_to_slave_nat (to_slave_nat);
3052 t.set_to_slave (get_output_handle ());
3053 t.winsize.ws_col = 80;
3054 t.winsize.ws_row = 25;
3055 t.master_pid = myself->pid;
3056
3057 dev ().parse (DEV_PTYM_MAJOR, unit);
3058
3059 t.master_is_running_as_service = is_running_as_service ();
3060
3061 termios_printf ("this %p, pty%d opened - from_pty <%p,%p>, to_pty %p",
3062 this, unit, from_slave_nat, get_handle (),
3063 get_output_handle ());
3064 return true;
3065
3066 err:
3067 __seterrno ();
3068 close_maybe (from_slave_nat);
3069 close_maybe (to_slave_nat);
3070 close_maybe (get_handle ());
3071 close_maybe (get_output_handle ());
3072 close_maybe (input_available_event);
3073 close_maybe (output_mutex);
3074 close_maybe (input_mutex);
3075 close_maybe (from_master_nat);
3076 close_maybe (to_master_nat);
3077 close_maybe (to_master);
3078 close_maybe (echo_r);
3079 close_maybe (echo_w);
3080 close_maybe (master_ctl);
3081 /* The from_master must be closed last so that the same pty is not
3082 allocated before cleaning up the other corresponding instances. */
3083 close_maybe (from_master);
3084 termios_printf ("pty%d open failed - failed to create %s", unit, errstr);
3085 return false;
3086 }
3087
3088 void
3089 fhandler_pty_master::fixup_after_fork (HANDLE parent)
3090 {
3091 DWORD wpid = GetCurrentProcessId ();
3092 fhandler_pty_master *arch = (fhandler_pty_master *) archetype;
3093 if (arch->dwProcessId != wpid)
3094 {
3095 tty& t = *get_ttyp ();
3096 if (myself->pid == t.master_pid)
3097 {
3098 t.set_from_master_nat (arch->from_master_nat);
3099 t.set_from_master (arch->from_master);
3100 t.set_to_master_nat (arch->to_master_nat);
3101 t.set_to_master (arch->to_master);
3102 }
3103 arch->dwProcessId = wpid;
3104 }
3105 from_master_nat = arch->from_master_nat;
3106 from_master = arch->from_master;
3107 to_master_nat = arch->to_master_nat;
3108 to_master = arch->to_master;
3109 #if 0 /* Not sure if this is necessary. */
3110 from_slave_nat = arch->from_slave_nat;
3111 to_slave_nat = arch->to_slave_nat;
3112 #endif
3113 report_tty_counts (this, "inherited master", "");
3114 }
3115
3116 void
3117 fhandler_pty_master::fixup_after_exec ()
3118 {
3119 if (!close_on_exec ())
3120 fixup_after_fork (spawn_info->parent);
3121 else
3122 from_master_nat = from_master = to_master_nat = to_master =
3123 from_slave_nat = to_slave_nat = NULL;
3124 }
3125
3126 BOOL
3127 fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr,
3128 ssize_t& len, bool is_echo,
3129 tty *ttyp, bool is_nonblocking)
3130 {
3131 ssize_t towrite = len;
3132 BOOL res = TRUE;
3133 if (ttyp->ti.c_lflag & FLUSHO)
3134 return res; /* Discard write data */
3135 while (towrite)
3136 {
3137 if (!is_echo)
3138 {
3139 if (ttyp->output_stopped && is_nonblocking)
3140 {
3141 if (towrite < len)
3142 break;
3143 else
3144 {
3145 set_errno (EAGAIN);
3146 len = -1;
3147 return TRUE;
3148 }
3149 }
3150 while (ttyp->output_stopped)
3151 cygwait (10);
3152 }
3153
3154 if (!(ttyp->ti.c_oflag & OPOST)) // raw output mode
3155 {
3156 DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
3157 res = WriteFile (h, ptr, n, &n, NULL);
3158 if (!res)
3159 break;
3160 ptr = (char *) ptr + n;
3161 towrite -= n;
3162 }
3163 else // post-process output
3164 {
3165 char outbuf[OUT_BUFFER_SIZE + 1];
3166 char *buf = (char *)ptr;
3167 DWORD n = 0;
3168 ssize_t rc = 0;
3169 while (n < OUT_BUFFER_SIZE && rc < towrite)
3170 {
3171 switch (buf[rc])
3172 {
3173 case '\r':
3174 if ((ttyp->ti.c_oflag & ONOCR)
3175 && ttyp->column == 0)
3176 {
3177 rc++;
3178 continue;
3179 }
3180 if (ttyp->ti.c_oflag & OCRNL)
3181 {
3182 outbuf[n++] = '\n';
3183 rc++;
3184 }
3185 else
3186 {
3187 outbuf[n++] = buf[rc++];
3188 ttyp->column = 0;
3189 }
3190 break;
3191 case '\n':
3192 if (ttyp->ti.c_oflag & ONLCR)
3193 {
3194 outbuf[n++] = '\r';
3195 ttyp->column = 0;
3196 }
3197 if (ttyp->ti.c_oflag & ONLRET)
3198 ttyp->column = 0;
3199 outbuf[n++] = buf[rc++];
3200 break;
3201 default:
3202 outbuf[n++] = buf[rc++];
3203 ttyp->column++;
3204 break;
3205 }
3206 }
3207 res = WriteFile (h, outbuf, n, &n, NULL);
3208 if (!res)
3209 break;
3210 ptr = (char *) ptr + rc;
3211 towrite -= rc;
3212 }
3213 }
3214 len -= towrite;
3215 return res;
3216 }
3217
3218 /* Pseudo console supprot is realized using a tricky technic.
3219 PTY need the pseudo console handles, however, they cannot
3220 be retrieved by normal procedure. Therefore, run a helper
3221 process in a pseudo console and get them from the helper.
3222 Slave process will attach to the pseudo console in the
3223 helper process using AttachConsole(). */
3224 bool
3225 fhandler_pty_slave::setup_pseudoconsole (bool nopcon)
3226 {
3227 /* Setting switch_to_pcon_in is necessary even if
3228 pseudo console will not be activated. */
3229 fhandler_base *fh = ::cygheap->fdtab[0];
3230 if (fh && fh->get_major () == DEV_PTYS_MAJOR)
3231 {
3232 fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
3233 ptys->get_ttyp ()->switch_to_pcon_in = true;
3234 if (!pcon_pid_alive (ptys->get_ttyp ()->pcon_pid))
3235 ptys->get_ttyp ()->pcon_pid = myself->exec_dwProcessId;
3236 }
3237
3238 if (nopcon)
3239 return false;
3240
3241 /* If the legacy console mode is enabled, pseudo console seems
3242 not to work as expected. To determine console mode, registry
3243 key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
3244 reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
3245 if (reg.error ())
3246 return false;
3247 if (reg.get_dword (L"ForceV2", 1) == 0)
3248 {
3249 termios_printf ("Pseudo console is disabled "
3250 "because the legacy console mode is enabled.");
3251 return false;
3252 }
3253
3254 HANDLE hpConIn, hpConOut;
3255 if (get_ttyp ()->pcon_activated)
3256 {
3257 if (GetStdHandle (STD_INPUT_HANDLE) == get_handle ())
3258 { /* Send CSI6n just for requesting transfer input. */
3259 DWORD n;
3260 WaitForSingleObject (input_mutex, mutex_timeout);
3261 get_ttyp ()->req_xfer_input = true;
3262 get_ttyp ()->pcon_start = true;
3263 get_ttyp ()->pcon_start_pid = myself->pid;
3264 WriteFile (get_output_handle (), "\033[6n", 4, &n, NULL);
3265 ReleaseMutex (input_mutex);
3266 while (get_ttyp ()->pcon_start)
3267 Sleep (1);
3268 }
3269 /* Attach to the pseudo console which already exits. */
3270 HANDLE pcon_owner =
3271 OpenProcess (PROCESS_DUP_HANDLE, FALSE, get_ttyp ()->pcon_pid);
3272 if (pcon_owner == NULL)
3273 return false;
3274 DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_in,
3275 GetCurrentProcess (), &hpConIn,
3276 0, TRUE, DUPLICATE_SAME_ACCESS);
3277 DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_out,
3278 GetCurrentProcess (), &hpConOut,
3279 0, TRUE, DUPLICATE_SAME_ACCESS);
3280 CloseHandle (pcon_owner);
3281 FreeConsole ();
3282 AttachConsole (get_ttyp ()->pcon_pid);
3283 goto skip_create;
3284 }
3285
3286 STARTUPINFOEXW si;
3287 PROCESS_INFORMATION pi;
3288 HANDLE hello, goodbye;
3289 HANDLE hr, hw;
3290 HPCON hpcon;
3291
3292 do
3293 {
3294 COORD size = {
3295 (SHORT) get_ttyp ()->winsize.ws_col,
3296 (SHORT) get_ttyp ()->winsize.ws_row
3297 };
3298 const DWORD inherit_cursor = 1;
3299 hpcon = NULL;
3300 SetLastError (ERROR_SUCCESS);
3301 HRESULT res = CreatePseudoConsole (size, get_handle_nat (),
3302 get_output_handle_nat (),
3303 inherit_cursor, &hpcon);
3304 if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
3305 {
3306 if (res != S_OK)
3307 system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
3308 GetLastError (), res);
3309 goto fallback;
3310 }
3311
3312 SIZE_T bytesRequired;
3313 InitializeProcThreadAttributeList (NULL, 2, 0, &bytesRequired);
3314 ZeroMemory (&si, sizeof (si));
3315 si.StartupInfo.cb = sizeof (STARTUPINFOEXW);
3316 si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
3317 HeapAlloc (GetProcessHeap (), 0, bytesRequired);
3318 if (si.lpAttributeList == NULL)
3319 goto cleanup_pseudo_console;
3320 if (!InitializeProcThreadAttributeList (si.lpAttributeList,
3321 2, 0, &bytesRequired))
3322 goto cleanup_heap;
3323 if (!UpdateProcThreadAttribute (si.lpAttributeList,
3324 0,
3325 PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
3326 hpcon, sizeof (hpcon), NULL, NULL))
3327
3328 goto cleanup_heap;
3329
3330 hello = CreateEvent (&sec_none, true, false, NULL);
3331 goodbye = CreateEvent (&sec_none, true, false, NULL);
3332 CreatePipe (&hr, &hw, &sec_none, 0);
3333
3334 HANDLE handles_to_inherit[] = {hello, goodbye, hw};
3335 if (!UpdateProcThreadAttribute (si.lpAttributeList,
3336 0,
3337 PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
3338 handles_to_inherit,
3339 sizeof (handles_to_inherit),
3340 NULL, NULL))
3341 goto cleanup_event_and_pipes;
3342
3343 /* Execute helper process */
3344 WCHAR cmd[MAX_PATH];
3345 path_conv helper ("/bin/cygwin-console-helper.exe");
3346 size_t len = helper.get_wide_win32_path_len ();
3347 helper.get_wide_win32_path (cmd);
3348 __small_swprintf (cmd + len, L" %p %p %p", hello, goodbye, hw);
3349 si.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
3350 si.StartupInfo.hStdInput = NULL;
3351 si.StartupInfo.hStdOutput = NULL;
3352 si.StartupInfo.hStdError = NULL;
3353
3354 get_ttyp ()->pcon_activated = true;
3355 get_ttyp ()->pcon_start = true;
3356 get_ttyp ()->pcon_start_pid = myself->pid;
3357 if (!CreateProcessW (NULL, cmd, &sec_none, &sec_none,
3358 TRUE, EXTENDED_STARTUPINFO_PRESENT,
3359 NULL, NULL, &si.StartupInfo, &pi))
3360 goto cleanup_event_and_pipes;
3361
3362 for (;;)
3363 {
3364 DWORD wait_result = WaitForSingleObject (hello, 500);
3365 if (wait_result == WAIT_OBJECT_0)
3366 break;
3367 if (wait_result != WAIT_TIMEOUT)
3368 goto cleanup_helper_with_hello;
3369 DWORD exit_code;
3370 if (!GetExitCodeProcess (pi.hProcess, &exit_code))
3371 goto cleanup_helper_with_hello;
3372 if (exit_code == STILL_ACTIVE)
3373 continue;
3374 if (exit_code != 0 ||
3375 WaitForSingleObject (hello, 500) != WAIT_OBJECT_0)
3376 goto cleanup_helper_with_hello;
3377 break;
3378 }
3379 CloseHandle (hello);
3380 CloseHandle (pi.hThread);
3381
3382 /* Duplicate pseudo console handles */
3383 DWORD rlen;
3384 char buf[64];
3385 if (!ReadFile (hr, buf, sizeof (buf), &rlen, NULL))
3386 goto cleanup_helper_process;
3387 buf[rlen] = '\0';
3388 sscanf (buf, "StdHandles=%p,%p", &hpConIn, &hpConOut);
3389 if (!DuplicateHandle (pi.hProcess, hpConIn,
3390 GetCurrentProcess (), &hpConIn, 0,
3391 TRUE, DUPLICATE_SAME_ACCESS))
3392 goto cleanup_helper_process;
3393 if (!DuplicateHandle (pi.hProcess, hpConOut,
3394 GetCurrentProcess (), &hpConOut, 0,
3395 TRUE, DUPLICATE_SAME_ACCESS))
3396 goto cleanup_pcon_in;
3397
3398 CloseHandle (hr);
3399 CloseHandle (hw);
3400 DeleteProcThreadAttributeList (si.lpAttributeList);
3401 HeapFree (GetProcessHeap (), 0, si.lpAttributeList);
3402
3403 /* Attach to pseudo console */
3404 FreeConsole ();
3405 AttachConsole (pi.dwProcessId);
3406
3407 /* Terminate helper process */
3408 SetEvent (goodbye);
3409 WaitForSingleObject (pi.hProcess, INFINITE);
3410 CloseHandle (goodbye);
3411 CloseHandle (pi.hProcess);
3412 }
3413 while (false);
3414
3415 skip_create:
3416 do
3417 {
3418 /* Fixup handles */
3419 HANDLE orig_input_handle_nat = get_handle_nat ();
3420 HANDLE orig_output_handle_nat = get_output_handle_nat ();
3421 cygheap_fdenum cfd (false);
3422 while (cfd.next () >= 0)
3423 if (cfd->get_device () == get_device ())
3424 {
3425 fhandler_base *fh = cfd;
3426 fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
3427 if (ptys->get_handle_nat () == orig_input_handle_nat)
3428 ptys->set_handle_nat (hpConIn);
3429 if (ptys->get_output_handle_nat () == orig_output_handle_nat)
3430 ptys->set_output_handle_nat (hpConOut);
3431 }
3432 CloseHandle (orig_input_handle_nat);
3433 CloseHandle (orig_output_handle_nat);
3434 }
3435 while (false);
3436
3437 if (!pcon_pid_alive (get_ttyp ()->pcon_pid))
3438 get_ttyp ()->pcon_pid = myself->exec_dwProcessId;
3439
3440 if (hpcon && pcon_pid_self (get_ttyp ()->pcon_pid))
3441 {
3442 HPCON_INTERNAL *hp = (HPCON_INTERNAL *) hpcon;
3443 get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
3444 get_ttyp ()->h_pcon_condrv_reference = hp->hConDrvReference;
3445 get_ttyp ()->h_pcon_conhost_process = hp->hConHostProcess;
3446 DuplicateHandle (GetCurrentProcess (), hpConIn,
3447 GetCurrentProcess (), &get_ttyp ()->h_pcon_in,
3448 0, TRUE, DUPLICATE_SAME_ACCESS);
3449 DuplicateHandle (GetCurrentProcess (), hpConOut,
3450 GetCurrentProcess (), &get_ttyp ()->h_pcon_out,
3451 0, TRUE, DUPLICATE_SAME_ACCESS);
3452 /* Discard the pseudo console handler container here.
3453 Reconstruct it temporary when it is needed. */
3454 HeapFree (GetProcessHeap (), 0, hp);
3455 }
3456
3457 if (get_ttyp ()->previous_code_page)
3458 SetConsoleCP (get_ttyp ()->previous_code_page);
3459 if (get_ttyp ()->previous_output_code_page)
3460 SetConsoleOutputCP (get_ttyp ()->previous_output_code_page);
3461
3462 if (get_ttyp ()->getpgid () == myself->pgid)
3463 {
3464 termios &t = get_ttyp ()->ti;
3465 DWORD mode;
3466 /* Set input mode */
3467 GetConsoleMode (hpConIn, &mode);
3468 mode &= ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
3469 if (t.c_lflag & ECHO)
3470 mode |= ENABLE_ECHO_INPUT;
3471 if (t.c_lflag & ICANON)
3472 mode |= ENABLE_LINE_INPUT;
3473 if (mode & ENABLE_ECHO_INPUT && !(mode & ENABLE_LINE_INPUT))
3474 /* This is illegal, so turn off the echo here, and fake it
3475 when we read the characters */
3476 mode &= ~ENABLE_ECHO_INPUT;
3477 if (t.c_lflag & ISIG)
3478 mode |= ENABLE_PROCESSED_INPUT;
3479 SetConsoleMode (hpConIn, mode);
3480 /* Set output mode */
3481 GetConsoleMode (hpConOut, &mode);
3482 mode &= ~DISABLE_NEWLINE_AUTO_RETURN;
3483 if (!(t.c_oflag & OPOST) || !(t.c_oflag & ONLCR))
3484 mode |= DISABLE_NEWLINE_AUTO_RETURN;
3485 SetConsoleMode (hpConOut, mode);
3486 }
3487
3488 return true;
3489
3490 cleanup_helper_with_hello:
3491 CloseHandle (hello);
3492 CloseHandle (pi.hThread);
3493 goto cleanup_helper_process;
3494 cleanup_pcon_in:
3495 CloseHandle (hpConIn);
3496 cleanup_helper_process:
3497 SetEvent (goodbye);
3498 WaitForSingleObject (pi.hProcess, INFINITE);
3499 CloseHandle (pi.hProcess);
3500 goto skip_close_hello;
3501 cleanup_event_and_pipes:
3502 CloseHandle (hello);
3503 skip_close_hello:
3504 get_ttyp ()->pcon_start = false;
3505 get_ttyp ()->pcon_start_pid = 0;
3506 get_ttyp ()->pcon_activated = false;
3507 CloseHandle (goodbye);
3508 CloseHandle (hr);
3509 CloseHandle (hw);
3510 cleanup_heap:
3511 HeapFree (GetProcessHeap (), 0, si.lpAttributeList);
3512 cleanup_pseudo_console:
3513 if (hpcon)
3514 {
3515 HPCON_INTERNAL *hp = (HPCON_INTERNAL *) hpcon;
3516 HANDLE tmp = hp->hConHostProcess;
3517 ClosePseudoConsole (hpcon);
3518 CloseHandle (tmp);
3519 }
3520 fallback:
3521 return false;
3522 }
3523
3524 /* The function close_pseudoconsole() should be static so that it can
3525 be called even after the fhandler_pty_slave instance is deleted. */
3526 void
3527 fhandler_pty_slave::close_pseudoconsole (tty *ttyp, DWORD force_switch_to)
3528 {
3529 DWORD switch_to = 0;
3530 if (force_switch_to)
3531 {
3532 switch_to = force_switch_to;
3533 ttyp->setpgid (force_switch_to + MAX_PID);
3534 }
3535 else if (pcon_pid_self (ttyp->pcon_pid))
3536 {
3537 /* Search another process which attaches to the pseudo console */
3538 DWORD current_pid = myself->exec_dwProcessId ?: myself->dwProcessId;
3539 switch_to = get_console_process_id (current_pid, false, true, true);
3540 }
3541 if (ttyp->pcon_activated)
3542 {
3543 ttyp->previous_code_page = GetConsoleCP ();
3544 ttyp->previous_output_code_page = GetConsoleOutputCP ();
3545 if (pcon_pid_self (ttyp->pcon_pid))
3546 {
3547 if (switch_to)
3548 {
3549 /* Change pseudo console owner to another process */
3550 HANDLE new_owner =
3551 OpenProcess (PROCESS_DUP_HANDLE, FALSE, switch_to);
3552 HANDLE new_write_pipe = NULL;
3553 HANDLE new_condrv_reference = NULL;
3554 HANDLE new_conhost_process = NULL;
3555 HANDLE new_pcon_in = NULL, new_pcon_out = NULL;
3556 DuplicateHandle (GetCurrentProcess (),
3557 ttyp->h_pcon_write_pipe,
3558 new_owner, &new_write_pipe,
3559 0, TRUE, DUPLICATE_SAME_ACCESS);
3560 DuplicateHandle (GetCurrentProcess (),
3561 ttyp->h_pcon_condrv_reference,
3562 new_owner, &new_condrv_reference,
3563 0, TRUE, DUPLICATE_SAME_ACCESS);
3564 DuplicateHandle (GetCurrentProcess (),
3565 ttyp->h_pcon_conhost_process,
3566 new_owner, &new_conhost_process,
3567 0, TRUE, DUPLICATE_SAME_ACCESS);
3568 DuplicateHandle (GetCurrentProcess (), ttyp->h_pcon_in,
3569 new_owner, &new_pcon_in,
3570 0, TRUE, DUPLICATE_SAME_ACCESS);
3571 DuplicateHandle (GetCurrentProcess (), ttyp->h_pcon_out,
3572 new_owner, &new_pcon_out,
3573 0, TRUE, DUPLICATE_SAME_ACCESS);
3574 CloseHandle (new_owner);
3575 CloseHandle (ttyp->h_pcon_write_pipe);
3576 CloseHandle (ttyp->h_pcon_condrv_reference);
3577 CloseHandle (ttyp->h_pcon_conhost_process);
3578 CloseHandle (ttyp->h_pcon_in);
3579 CloseHandle (ttyp->h_pcon_out);
3580 ttyp->pcon_pid = switch_to;
3581 ttyp->h_pcon_write_pipe = new_write_pipe;
3582 ttyp->h_pcon_condrv_reference = new_condrv_reference;
3583 ttyp->h_pcon_conhost_process = new_conhost_process;
3584 ttyp->h_pcon_in = new_pcon_in;
3585 ttyp->h_pcon_out = new_pcon_out;
3586 FreeConsole ();
3587 pinfo p (myself->ppid);
3588 if (p)
3589 {
3590 if (!AttachConsole (p->dwProcessId))
3591 AttachConsole (ATTACH_PARENT_PROCESS);
3592 }
3593 else
3594 AttachConsole (ATTACH_PARENT_PROCESS);
3595 }
3596 else
3597 { /* Close pseudo console */
3598 FreeConsole ();
3599 pinfo p (myself->ppid);
3600 if (p)
3601 {
3602 if (!AttachConsole (p->dwProcessId))
3603 AttachConsole (ATTACH_PARENT_PROCESS);
3604 }
3605 else
3606 AttachConsole (ATTACH_PARENT_PROCESS);
3607 /* Reconstruct pseudo console handler container here for close */
3608 HPCON_INTERNAL *hp =
3609 (HPCON_INTERNAL *) HeapAlloc (GetProcessHeap (), 0,
3610 sizeof (HPCON_INTERNAL));
3611 hp->hWritePipe = ttyp->h_pcon_write_pipe;
3612 hp->hConDrvReference = ttyp->h_pcon_condrv_reference;
3613 hp->hConHostProcess = ttyp->h_pcon_conhost_process;
3614 /* HeapFree() will be called in ClosePseudoConsole() */
3615 ClosePseudoConsole ((HPCON) hp);
3616 CloseHandle (ttyp->h_pcon_conhost_process);
3617 ttyp->pcon_activated = false;
3618 ttyp->switch_to_pcon_in = false;
3619 ttyp->pcon_pid = 0;
3620 ttyp->pcon_start = false;
3621 ttyp->pcon_start_pid = 0;
3622 }
3623 }
3624 else
3625 {
3626 FreeConsole ();
3627 pinfo p (myself->ppid);
3628 if (p)
3629 {
3630 if (!AttachConsole (p->dwProcessId))
3631 AttachConsole (ATTACH_PARENT_PROCESS);
3632 }
3633 else
3634 AttachConsole (ATTACH_PARENT_PROCESS);
3635 }
3636 }
3637 else if (pcon_pid_self (ttyp->pcon_pid))
3638 {
3639 if (switch_to)
3640 ttyp->pcon_pid = switch_to;
3641 else
3642 {
3643 ttyp->pcon_pid = 0;
3644 ttyp->switch_to_pcon_in = false;
3645 }
3646 }
3647 }
3648
3649 static bool
3650 has_ansi_escape_sequences (const WCHAR *env)
3651 {
3652 /* Retrieve TERM name */
3653 const char *term = NULL;
3654 char term_str[260];
3655 if (env)
3656 {
3657 for (const WCHAR *p = env; *p != L'\0'; p += wcslen (p) + 1)
3658 if (swscanf (p, L"TERM=%236s", term_str) == 1)
3659 {
3660 term = term_str;
3661 break;
3662 }
3663 }
3664 else
3665 term = getenv ("TERM");
3666
3667 if (!term)
3668 return false;
3669
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);
3686
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;
3716 }
3717
3718 bool
3719 fhandler_pty_slave::term_has_pcon_cap (const WCHAR *env)
3720 {
3721 if (get_ttyp ()->pcon_cap_checked)
3722 return get_ttyp ()->has_csi6n;
3723
3724 DWORD n;
3725 char buf[1024];
3726 char *p;
3727 int len;
3728 int wait_cnt = 0;
3729
3730 /* Check if terminal has ANSI escape sequence. */
3731 if (!has_ansi_escape_sequences (env))
3732 goto maybe_dumb;
3733
3734 /* Check if terminal has CSI6n */
3735 WaitForSingleObject (pcon_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;
3746 do
3747 {
3748 if (::bytes_available (n, get_handle_nat ()) && n)
3749 {
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;
3762 }
3763 else if (++wait_cnt > 100) /* Timeout */
3764 goto not_has_csi6n;
3765 else
3766 Sleep (1);
3767 }
3768 while (len);
3769 get_ttyp ()->pcon_activated = false;
3770 get_ttyp ()->pcon_pid = 0;
3771 ReleaseMutex (pcon_mutex);
3772 if (len == 0)
3773 goto not_has_csi6n;
3774
3775 get_ttyp ()->has_csi6n = true;
3776 get_ttyp ()->pcon_cap_checked = true;
3777
3778 return true;
3779
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 (pcon_mutex);
3788 maybe_dumb:
3789 get_ttyp ()->pcon_cap_checked = true;
3790 return false;
3791 }
3792
3793 void
3794 fhandler_pty_slave::create_invisible_console ()
3795 {
3796 if (get_ttyp ()->need_invisible_console)
3797 {
3798 /* Detach from console device and create new invisible console. */
3799 FreeConsole();
3800 fhandler_console::need_invisible (true);
3801 get_ttyp ()->need_invisible_console = false;
3802 get_ttyp ()->invisible_console_pid = myself->pid;
3803 }
3804 if (get_ttyp ()->invisible_console_pid
3805 && !pinfo (get_ttyp ()->invisible_console_pid))
3806 /* If primary slave process does not exist anymore,
3807 this process becomes the primary. */
3808 get_ttyp ()->invisible_console_pid = myself->pid;
3809 }
3810
3811 void
3812 fhandler_pty_master::get_master_thread_param (master_thread_param_t *p)
3813 {
3814 p->from_master_nat = from_master_nat;
3815 p->from_master = from_master;
3816 p->to_master_nat = to_master_nat;
3817 p->to_master = to_master;
3818 p->to_slave_nat = to_slave_nat;
3819 p->to_slave = get_output_handle ();
3820 p->master_ctl = master_ctl;
3821 p->input_available_event = input_available_event;
3822 SetEvent (thread_param_copied_event);
3823 }
3824
3825 void
3826 fhandler_pty_master::get_master_fwd_thread_param (master_fwd_thread_param_t *p)
3827 {
3828 p->to_master = to_master;
3829 p->from_slave_nat = from_slave_nat;
3830 p->output_mutex = output_mutex;
3831 p->ttyp = get_ttyp ();
3832 SetEvent (thread_param_copied_event);
3833 }
3834
3835 #define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
3836 #define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
3837 void
3838 fhandler_pty_slave::transfer_input (tty::xfer_dir dir, HANDLE from, tty *ttyp,
3839 HANDLE input_available_event)
3840 {
3841 HANDLE to;
3842 if (dir == tty::to_nat)
3843 to = ttyp->to_slave_nat ();
3844 else
3845 to = ttyp->to_slave ();
3846
3847 pinfo p (ttyp->master_pid);
3848 HANDLE pty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId);
3849 if (pty_owner)
3850 {
3851 DuplicateHandle (pty_owner, to, GetCurrentProcess (), &to,
3852 0, TRUE, DUPLICATE_SAME_ACCESS);
3853 CloseHandle (pty_owner);
3854 }
3855 else
3856 {
3857 char pipe[MAX_PATH];
3858 __small_sprintf (pipe,
3859 "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
3860 &cygheap->installation_key, ttyp->get_minor ());
3861 pipe_request req = { GetCurrentProcessId () };
3862 pipe_reply repl;
3863 DWORD len;
3864 if (!CallNamedPipe (pipe, &req, sizeof req,
3865 &repl, sizeof repl, &len, 500))
3866 return; /* What can we do? */
3867 if (dir == tty::to_nat)
3868 to = repl.to_slave_nat;
3869 else
3870 to = repl.to_slave;
3871 }
3872
3873 UINT cp_from = 0, cp_to = 0;
3874
3875 if (dir == tty::to_nat)
3876 {
3877 cp_from = ttyp->term_code_page;
3878 if (ttyp->pcon_activated)
3879 cp_to = CP_UTF8;
3880 else
3881 cp_to = GetConsoleCP ();
3882 }
3883 else
3884 {
3885 cp_from = GetConsoleCP ();
3886 cp_to = ttyp->term_code_page;
3887 }
3888
3889 tmp_pathbuf tp;
3890 char *buf = tp.c_get ();
3891
3892 bool transfered = false;
3893
3894 if (dir == tty::to_cyg && ttyp->pcon_activated)
3895 { /* from handle is console handle */
3896 INPUT_RECORD r[INREC_SIZE];
3897 DWORD n;
3898 while (PeekConsoleInputA (from, r, INREC_SIZE, &n) && n)
3899 {
3900 ReadConsoleInputA (from, r, n, &n);
3901 if (ttyp->discard_input)
3902 continue;
3903 int len = 0;
3904 char *ptr = buf;
3905 for (DWORD i = 0; i < n; i++)
3906 if (r[i].EventType == KEY_EVENT && r[i].Event.KeyEvent.bKeyDown)
3907 {
3908 DWORD ctrl_key_state = r[i].Event.KeyEvent.dwControlKeyState;
3909 if (r[i].Event.KeyEvent.uChar.AsciiChar)
3910 {
3911 if ((ctrl_key_state & ALT_PRESSED)
3912 && r[i].Event.KeyEvent.uChar.AsciiChar <= 0x7f)
3913 buf[len++] = '\033'; /* Meta */
3914 buf[len++] = r[i].Event.KeyEvent.uChar.AsciiChar;
3915 }
3916 /* Allow Ctrl-Space to emit ^@ */
3917 else if (r[i].Event.KeyEvent.wVirtualKeyCode == '2'
3918 && (ctrl_key_state & CTRL_PRESSED)
3919 && !(ctrl_key_state & ALT_PRESSED))
3920 buf[len++] = '\0';
3921 else
3922 { /* arrow/function keys */
3923 /* FIXME: The current code generates cygwin terminal
3924 sequence rather than xterm sequence. */
3925 char tmp[16];
3926 const char *add =
3927 fhandler_console::get_nonascii_key (r[i], tmp);
3928 if (add)
3929 {
3930 strcpy (buf + len, add);
3931 len += strlen (add);
3932 }
3933 }
3934 }
3935 if (cp_to != cp_from)
3936 {
3937 static mbstate_t mbp;
3938 char *mbbuf = tp.c_get ();
3939 size_t nlen = NT_MAX_PATH;
3940 convert_mb_str (cp_to, mbbuf, &nlen, cp_from, buf, len, &mbp);
3941 ptr = mbbuf;
3942 len = nlen;
3943 }
3944 /* Call WriteFile() line by line */
3945 char *p0 = ptr;
3946 char *p1 = ptr;
3947 while ((p1 = (char *) memchr (p0, '\r', len - (p0 - ptr))))
3948 {
3949 *p1 = '\n';
3950 n = p1 - p0 + 1;
3951 if (n && WriteFile (to, p0, n, &n, NULL) && n)
3952 transfered = true;
3953 p0 = p1 + 1;
3954 }
3955 n = len - (p0 - ptr);
3956 if (n && WriteFile (to, p0, n, &n, NULL) && n)
3957 transfered = true;
3958 }
3959 }
3960 else
3961 {
3962 DWORD bytes_in_pipe;
3963 while (::bytes_available (bytes_in_pipe, from) && bytes_in_pipe)
3964 {
3965 DWORD n = MIN (bytes_in_pipe, NT_MAX_PATH);
3966 ReadFile (from, buf, n, &n, NULL);
3967 if (ttyp->discard_input)
3968 continue;
3969 char *ptr = buf;
3970 if (dir == tty::to_nat)
3971 {
3972 char *p = buf;
3973 if (ttyp->pcon_activated)
3974 while ((p = (char *) memchr (p, '\n', n - (p - buf))))
3975 *p = '\r';
3976 else
3977 while ((p = (char *) memchr (p, '\r', n - (p - buf))))
3978 *p = '\n';
3979 }
3980 if (cp_to != cp_from)
3981 {
3982 static mbstate_t mbp;
3983 char *mbbuf = tp.c_get ();
3984 size_t nlen = NT_MAX_PATH;
3985 convert_mb_str (cp_to, mbbuf, &nlen, cp_from, buf, n, &mbp);
3986 ptr = mbbuf;
3987 n = nlen;
3988 }
3989 if (n && WriteFile (to, ptr, n, &n, NULL) && n)
3990 transfered = true;;
3991 }
3992 }
3993
3994 if (dir == tty::to_nat)
3995 ResetEvent (input_available_event);
3996 else if (transfered)
3997 SetEvent (input_available_event);
3998 ttyp->pcon_input_state = dir;
3999 ttyp->discard_input = false;
4000 }
This page took 0.216962 seconds and 5 git commands to generate.