3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
11 #include <sys/param.h>
12 #include <cygwin/acl.h>
13 #include <cygwin/kd.h>
23 #include "shared_info.h"
24 #include "cygthread.h"
25 #include "child_info.h"
26 #include <asm/socket.h>
32 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
33 #define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016
34 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
36 extern "C" int sscanf (const char *, const char *, ...);
38 #define close_maybe(h) \
40 if (h && h != INVALID_HANDLE_VALUE) \
44 /* pty master control pipe messages */
49 /* The name *nat* comes from 'native' which means non-cygwin
50 (native windows). They are used for non-cygwin process. */
52 HANDLE from_master_nat
;
61 HANDLE NO_COPY attach_mutex
;
63 DWORD
acquire_attach_mutex (DWORD t
)
67 return WaitForSingleObject (attach_mutex
, t
);
70 void release_attach_mutex (void)
74 ReleaseMutex (attach_mutex
);
77 inline static bool process_alive (DWORD pid
);
79 /* This functions looks for a process which attached to the same console
80 with current process and is matched to given conditions:
81 match: If true, return given pid if the process pid attaches to the
82 same console, otherwise, return 0. If false, return pid except
84 cygwin: return only process's pid which has cygwin pid.
85 stub_only: return only stub process's pid of non-cygwin process. */
87 fhandler_pty_common::get_console_process_id (DWORD pid
, bool match
,
88 bool cygwin
, bool stub_only
,
92 DWORD
*list
= (DWORD
*) tp
.c_get ();
93 const DWORD buf_size
= NT_MAX_PATH
/ sizeof (DWORD
);
95 DWORD num
= GetConsoleProcessList (list
, buf_size
);
96 if (num
== 0 || num
> buf_size
)
99 DWORD res_pri
= 0, res
= 0;
100 /* Last one is the oldest. */
101 /* https://github.com/microsoft/terminal/issues/95 */
102 for (int i
= (int) num
- 1; i
>= 0; i
--)
103 if ((match
&& list
[i
] == pid
) || (!match
&& list
[i
] != pid
))
112 pinfo
p (cygwin_pid (list
[i
]));
113 if (nat
&& !!p
&& !ISSTATE(p
, PID_NOTCYGWIN
))
115 if (!!p
&& p
->exec_dwProcessId
)
117 res_pri
= stub_only
? p
->exec_dwProcessId
: list
[i
];
120 if (!p
&& !res
&& process_alive (list
[i
]) && stub_only
)
122 if (!!p
&& !res
&& !stub_only
)
126 return res_pri
?: res
;
129 static bool isHybrid
; /* Set true if the active pipe is set to nat pipe
130 owned by myself even though the current process
131 is a cygwin process. */
132 static HANDLE h_gdb_inferior
; /* Handle of GDB inferior process. */
135 set_switch_to_nat_pipe (HANDLE
*in
, HANDLE
*out
, HANDLE
*err
)
137 cygheap_fdenum
cfd (false);
139 fhandler_base
*replace_in
= NULL
, *replace_out
= NULL
, *replace_err
= NULL
;
140 fhandler_pty_slave
*ptys
= NULL
;
141 while ((fd
= cfd
.next ()) >= 0)
143 if (*in
== cfd
->get_handle () ||
144 (fd
== 0 && *in
== GetStdHandle (STD_INPUT_HANDLE
)))
145 replace_in
= (fhandler_base
*) cfd
;
146 if (*out
== cfd
->get_output_handle () ||
147 (fd
== 1 && *out
== GetStdHandle (STD_OUTPUT_HANDLE
)))
148 replace_out
= (fhandler_base
*) cfd
;
149 if (*err
== cfd
->get_output_handle () ||
150 (fd
== 2 && *err
== GetStdHandle (STD_ERROR_HANDLE
)))
151 replace_err
= (fhandler_base
*) cfd
;
152 if (cfd
->get_device () == (dev_t
) myself
->ctty
)
154 fhandler_base
*fh
= cfd
;
155 if (*in
== fh
->get_handle ()
156 || *out
== fh
->get_output_handle ()
157 || *err
== fh
->get_output_handle ())
158 ptys
= (fhandler_pty_slave
*) fh
;
162 ptys
->set_switch_to_nat_pipe ();
164 *in
= replace_in
->get_handle_nat ();
166 *out
= replace_out
->get_output_handle_nat ();
168 *err
= replace_err
->get_output_handle_nat ();
171 /* Determine if the given path is cygwin binary. */
173 path_iscygexec_a_w (LPCSTR na
, LPSTR ca
, LPCWSTR nw
, LPWSTR cw
)
177 char *prog
=tp
.c_get ();
180 __small_sprintf (prog
, "%s", na
);
181 find_exec (prog
, path
);
185 __small_sprintf (prog
, "%W", nw
);
186 find_exec (prog
, path
);
191 __small_sprintf (prog
, "%s", ca
);
193 __small_sprintf (prog
, "%W", cw
);
199 if ((p1
= strchr (p
, ' ')) || (p1
= p
+ strlen (p
)))
205 find_exec (prog
, path
);
210 find_exec (prog
, path
);
212 while (!path
.exists() && *p
);
214 const char *argv
[] = {"", NULL
}; /* Dummy */
216 av1
.setup ("", path
, "", 1, argv
, false);
217 return path
.iscygexec ();
221 fhandler_termios::path_iscygexec_a (LPCSTR n
, LPSTR c
)
223 return path_iscygexec_a_w (n
, c
, NULL
, NULL
);
227 fhandler_termios::path_iscygexec_w (LPCWSTR n
, LPWSTR c
)
229 return path_iscygexec_a_w (NULL
, NULL
, n
, c
);
232 static bool atexit_func_registered
= false;
233 static bool debug_process
= false;
240 cygheap_fdenum
cfd (false);
241 while (cfd
.next () >= 0)
242 if (cfd
->get_device () == (dev_t
) myself
->ctty
)
244 DWORD force_switch_to
= 0;
245 if (WaitForSingleObject (h_gdb_inferior
, 0) == WAIT_TIMEOUT
247 force_switch_to
= GetProcessId (h_gdb_inferior
);
248 fhandler_base
*fh
= cfd
;
249 fhandler_pty_slave
*ptys
= (fhandler_pty_slave
*) fh
;
250 tty
*ttyp
= (tty
*) ptys
->tc ();
252 GetStdHandle (STD_INPUT_HANDLE
) == ptys
->get_handle ();
253 fhandler_pty_slave::handle_set_t handles
=
255 ptys
->get_handle_nat (),
256 ptys
->get_input_available_event (),
260 fhandler_pty_slave::cleanup_for_non_cygwin_app (&handles
, ttyp
,
265 CloseHandle (h_gdb_inferior
);
269 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
270 /* CreateProcess() is hooked for GDB etc. */
271 DEF_HOOK (CreateProcessA
);
272 DEF_HOOK (CreateProcessW
);
275 CreateProcessA_Hooked
276 (LPCSTR n
, LPSTR c
, LPSECURITY_ATTRIBUTES pa
, LPSECURITY_ATTRIBUTES ta
,
277 BOOL inh
, DWORD f
, LPVOID e
, LPCSTR d
,
278 LPSTARTUPINFOA si
, LPPROCESS_INFORMATION pi
)
280 STARTUPINFOEXA siex
= {0, };
281 if (si
->cb
== sizeof (STARTUPINFOEXA
))
282 siex
= *(STARTUPINFOEXA
*)si
;
284 siex
.StartupInfo
= *si
;
285 STARTUPINFOA
*siov
= &siex
.StartupInfo
;
286 if (!(si
->dwFlags
& STARTF_USESTDHANDLES
))
288 siov
->dwFlags
|= STARTF_USESTDHANDLES
;
289 siov
->hStdInput
= GetStdHandle (STD_INPUT_HANDLE
);
290 siov
->hStdOutput
= GetStdHandle (STD_OUTPUT_HANDLE
);
291 siov
->hStdError
= GetStdHandle (STD_ERROR_HANDLE
);
293 bool path_iscygexec
= fhandler_termios::path_iscygexec_a (n
, c
);
295 set_switch_to_nat_pipe (&siov
->hStdInput
, &siov
->hStdOutput
,
297 BOOL ret
= CreateProcessA_Orig (n
, c
, pa
, ta
, inh
, f
, e
, d
, siov
, pi
);
298 h_gdb_inferior
= pi
->hProcess
;
299 DuplicateHandle (GetCurrentProcess (), h_gdb_inferior
,
300 GetCurrentProcess (), &h_gdb_inferior
,
301 0, 0, DUPLICATE_SAME_ACCESS
);
302 debug_process
= !!(f
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
));
304 mutex_timeout
= 0; /* to avoid deadlock in GDB */
305 if (!atexit_func_registered
&& !path_iscygexec
)
307 atexit (atexit_func
);
308 atexit_func_registered
= true;
314 CreateProcessW_Hooked
315 (LPCWSTR n
, LPWSTR c
, LPSECURITY_ATTRIBUTES pa
, LPSECURITY_ATTRIBUTES ta
,
316 BOOL inh
, DWORD f
, LPVOID e
, LPCWSTR d
,
317 LPSTARTUPINFOW si
, LPPROCESS_INFORMATION pi
)
319 STARTUPINFOEXW siex
= {0, };
320 if (si
->cb
== sizeof (STARTUPINFOEXW
))
321 siex
= *(STARTUPINFOEXW
*)si
;
323 siex
.StartupInfo
= *si
;
324 STARTUPINFOW
*siov
= &siex
.StartupInfo
;
325 if (!(si
->dwFlags
& STARTF_USESTDHANDLES
))
327 siov
->dwFlags
|= STARTF_USESTDHANDLES
;
328 siov
->hStdInput
= GetStdHandle (STD_INPUT_HANDLE
);
329 siov
->hStdOutput
= GetStdHandle (STD_OUTPUT_HANDLE
);
330 siov
->hStdError
= GetStdHandle (STD_ERROR_HANDLE
);
332 bool path_iscygexec
= fhandler_termios::path_iscygexec_w (n
, c
);
334 set_switch_to_nat_pipe (&siov
->hStdInput
, &siov
->hStdOutput
,
336 BOOL ret
= CreateProcessW_Orig (n
, c
, pa
, ta
, inh
, f
, e
, d
, siov
, pi
);
337 h_gdb_inferior
= pi
->hProcess
;
338 DuplicateHandle (GetCurrentProcess (), h_gdb_inferior
,
339 GetCurrentProcess (), &h_gdb_inferior
,
340 0, 0, DUPLICATE_SAME_ACCESS
);
341 debug_process
= !!(f
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
));
343 mutex_timeout
= 0; /* to avoid deadlock in GDB */
344 if (!atexit_func_registered
&& !path_iscygexec
)
346 atexit (atexit_func
);
347 atexit_func_registered
= true;
353 convert_mb_str (UINT cp_to
, char *ptr_to
, size_t *len_to
,
354 UINT cp_from
, const char *ptr_from
, size_t len_from
,
358 wchar_t *wbuf
= tp
.w_get ();
360 char *tmpbuf
= tp
.c_get ();
361 memcpy (tmpbuf
, mbp
->__value
.__wchb
, mbp
->__count
);
362 if (mbp
->__count
+ len_from
> NT_MAX_PATH
)
363 len_from
= NT_MAX_PATH
- mbp
->__count
;
364 memcpy (tmpbuf
+ mbp
->__count
, ptr_from
, len_from
);
365 int total_len
= mbp
->__count
+ len_from
;
368 for (const char *p
= tmpbuf
; p
< tmpbuf
+ total_len
; p
+= mblen
)
369 /* Max bytes in multibyte char supported is 4. */
370 for (mblen
= 1; mblen
<= 4; mblen
++)
373 int l
= MultiByteToWideChar (cp_from
, MB_ERR_INVALID_CHARS
,
375 wbuf
+ wlen
, NT_MAX_PATH
- wlen
);
377 { /* Conversion Success */
382 { /* Conversion Fail */
383 l
= MultiByteToWideChar (cp_from
, 0, p
, 1,
384 wbuf
+ wlen
, NT_MAX_PATH
- wlen
);
389 else if (p
+ mblen
== tmpbuf
+ total_len
)
390 { /* Multibyte char incomplete */
391 memcpy (mbp
->__value
.__wchb
, p
, mblen
);
392 mbp
->__count
= mblen
;
395 /* Retry conversion with extended length */
397 *len_to
= WideCharToMultiByte (cp_to
, 0, wbuf
, wlen
,
398 ptr_to
, *len_to
, NULL
, NULL
);
402 bytes_available (DWORD
& n
, HANDLE h
)
406 bool succeeded
= PeekNamedPipe (h
, NULL
, 0, NULL
, &navail
, &nleft
);
408 /* nleft should always be the right choice unless something has written 0
409 bytes to the pipe. In that pathological case we return the actual number
410 of bytes available in the pipe. See cgf-000008 for more details. */
414 termios_printf ("PeekNamedPipe(%p) failed, %E", h
);
417 debug_only_printf ("n %u, nleft %u, navail %u", n
, nleft
, navail
);
422 fhandler_pty_common::bytes_available (DWORD
&n
)
424 return ::bytes_available (n
, get_handle ());
428 static class mutex_stack
440 fhandler_pty_master::flush_to_slave ()
442 WaitForSingleObject (input_mutex
, mutex_timeout
);
443 if (get_readahead_valid () && !(get_ttyp ()->ti
.c_lflag
& ICANON
))
445 ReleaseMutex (input_mutex
);
449 fhandler_pty_master::discard_input ()
455 WaitForSingleObject (input_mutex
, mutex_timeout
);
456 while (::bytes_available (bytes_in_pipe
, from_master
) && bytes_in_pipe
)
457 ReadFile (from_master
, buf
, sizeof(buf
), &n
, NULL
);
458 ResetEvent (input_available_event
);
459 if (!get_ttyp ()->pcon_activated
)
460 while (::bytes_available (bytes_in_pipe
, from_master_nat
) && bytes_in_pipe
)
461 ReadFile (from_master_nat
, buf
, sizeof(buf
), &n
, NULL
);
462 get_ttyp ()->discard_input
= true;
463 ReleaseMutex (input_mutex
);
467 fhandler_pty_common::__acquire_output_mutex (const char *fn
, int ln
,
470 if (strace
.active ())
471 strace
.prntf (_STRACE_TERMIOS
, fn
, "(%d): pty output_mutex (%p): waiting %d ms", ln
, output_mutex
, ms
);
472 DWORD res
= WaitForSingleObject (output_mutex
, ms
);
473 if (res
== WAIT_OBJECT_0
)
476 if (strace
.active ())
477 strace
.prntf (_STRACE_TERMIOS
, fn
, "(%d): pty output_mutex: acquired", ln
, res
);
481 ostack
[osi
].tname
= mythreadname ();
482 termios_printf ("acquired for %s:%d, osi %d", fn
, ln
, osi
);
490 fhandler_pty_common::__release_output_mutex (const char *fn
, int ln
)
492 if (ReleaseMutex (output_mutex
))
495 if (strace
.active ())
496 strace
.prntf (_STRACE_TERMIOS
, fn
, "(%d): pty output_mutex(%p) released", ln
, output_mutex
);
500 termios_printf ("released(%p) at %s:%d, osi %d", output_mutex
, fn
, ln
, osi
);
501 termios_printf (" for %s:%d (%s)", ostack
[osi
].fn
, ostack
[osi
].ln
, ostack
[osi
].tname
);
502 ostack
[osi
].ln
= -ln
;
508 system_printf ("couldn't release output mutex but we seem to own it, %E");
514 /* Process pty input. */
517 fhandler_pty_master::doecho (const void *str
, DWORD len
)
519 ssize_t towrite
= len
;
520 if (!process_opost_output (echo_w
, str
, towrite
, true,
521 get_ttyp (), is_nonblocking ()))
522 termios_printf ("Write to echo pipe failed, %E");
526 fhandler_pty_master::accept_input ()
531 char *p
= rabuf () + raixget ();
532 bytes_left
= eat_readahead (-1);
534 HANDLE write_to
= get_output_handle ();
536 if (to_be_read_from_nat_pipe ()
537 && get_ttyp ()->pty_input_state
== tty::to_nat
)
539 /* This code is reached if non-cygwin app is foreground and
540 pseudo console is not enabled. */
541 write_to
= to_slave_nat
; /* write to nat pipe rather than cyg pipe. */
543 /* Charset conversion for non-cygwin apps. */
545 pinfo pinfo_target
= pinfo (get_ttyp ()->invisible_console_pid
);
546 DWORD target_pid
= 0;
548 target_pid
= pinfo_target
->dwProcessId
;
551 /* Slave attaches to a different console than master.
552 Therefore reattach here. */
553 DWORD resume_pid
= attach_console_temporarily (target_pid
);
554 cp_to
= GetConsoleCP ();
555 resume_from_temporarily_attach (resume_pid
);
558 cp_to
= GetConsoleCP ();
560 if (get_ttyp ()->term_code_page
!= cp_to
)
562 static mbstate_t mbp
;
563 char *mbbuf
= tp
.c_get ();
564 size_t nlen
= NT_MAX_PATH
;
565 convert_mb_str (cp_to
, mbbuf
, &nlen
,
566 get_ttyp ()->term_code_page
, p
, bytes_left
, &mbp
);
574 termios_printf ("sending EOF to slave");
575 get_ttyp ()->read_retval
= 0;
582 paranoid_printf ("about to write %u chars to slave", bytes_left
);
583 /* Write line by line for transfer input. */
585 char *p_cr
= (char *) memchr (p0
, '\r', bytes_left
- (p0
- p
));
586 char *p_lf
= (char *) memchr (p0
, '\n', bytes_left
- (p0
- p
));
591 p_cr
? (p_lf
? ((p_cr
+ 1 == p_lf
)
592 ? p_lf
: min(p_cr
, p_lf
)) : p_cr
) : p_lf
;
594 rc
= WriteFile (write_to
, p0
, n
, &n
, NULL
);
598 p_cr
= (char *) memchr (p0
, '\r', bytes_left
- (p0
- p
));
599 p_lf
= (char *) memchr (p0
, '\n', bytes_left
- (p0
- p
));
601 if (rc
&& (n
= bytes_left
- (p0
- p
)))
603 rc
= WriteFile (write_to
, p0
, n
, &n
, NULL
);
607 if (!rc
&& written
== 0)
609 debug_printf ("error writing to pipe %p %E", write_to
);
610 get_ttyp ()->read_retval
= -1;
611 puts_readahead (p
, bytes_left
);
616 get_ttyp ()->read_retval
= 1;
618 bytes_left
-= written
;
621 debug_printf ("to_slave pipe is full");
622 puts_readahead (p
, bytes_left
);
628 if (write_to
== get_output_handle ())
629 SetEvent (input_available_event
); /* Set input_available_event only when
630 the data is written to cyg pipe. */
635 fhandler_pty_master::hit_eof ()
637 if (get_ttyp ()->was_opened
&& !get_ttyp ()->slave_alive ())
639 /* We have the only remaining open handle to this pty, and
640 the slave pty has been opened at least once. We treat
642 termios_printf ("all other handles closed");
648 /* Process pty output requests */
651 fhandler_pty_master::process_slave_output (char *buf
, size_t len
, int pktmode_on
)
654 char outbuf
[OUT_BUFFER_SIZE
];
669 /* Check echo pipe first. */
670 if (::bytes_available (echo_cnt
, echo_r
) && echo_cnt
> 0)
672 if (!bytes_available (n
))
682 /* tclush can finish here. */
686 if (is_nonblocking ())
692 pthread_testcancel ();
693 if (cygwait (NULL
, 10, cw_sig_eintr
) == WAIT_SIGNALED
694 && !_my_tls
.call_signal_handler ())
703 /* Set RLEN to the number of bytes to read from the pipe. */
708 if (pktmode_on
&& buf
)
710 *optr
++ = TIOCPKT_DATA
;
720 if (rlen
> sizeof outbuf
)
721 rlen
= sizeof outbuf
;
723 /* If echo pipe has data (something has been typed or pasted), prefer
724 it over slave output. */
727 if (!ReadFile (echo_r
, outbuf
, rlen
, &n
, NULL
))
729 termios_printf ("ReadFile on echo pipe failed, %E");
733 else if (!ReadFile (get_handle (), outbuf
, rlen
, &n
, NULL
))
735 termios_printf ("ReadFile failed, %E");
739 termios_printf ("bytes read %u", n
);
741 if (!buf
|| ((get_ttyp ()->ti
.c_lflag
& FLUSHO
)
742 && !get_ttyp ()->mask_flusho
))
743 continue; /* Discard read data */
745 memcpy (optr
, outbuf
, n
);
751 if (GetLastError () == ERROR_BROKEN_PIPE
)
763 set_mask_flusho (false);
764 termios_printf ("returning %d", rc
);
768 /* pty slave stuff */
770 fhandler_pty_slave::fhandler_pty_slave (int unit
, dev_t via
)
771 : fhandler_pty_common (), inuse (NULL
), output_handle_nat (NULL
),
772 io_handle_nat (NULL
), slave_reading (NULL
), num_reader (0)
774 dev_referred_via
= via
;
776 dev ().parse (DEV_PTYS_MAJOR
, unit
);
780 fhandler_pty_slave::open (int flags
, mode_t
)
783 HANDLE from_master_nat_local
, from_master_local
;
784 HANDLE to_master_nat_local
, to_master_local
;
787 &from_master_nat_local
, &input_available_event
, &input_mutex
, &inuse
,
788 &output_mutex
, &to_master_nat_local
, &pty_owner
, &to_master_local
,
789 &from_master_local
, &pipe_sw_mutex
,
793 for (HANDLE
**h
= handles
; *h
; h
++)
796 _tc
= cygwin_shared
->tty
[get_minor ()];
800 cygwin_shared
->tty
.attach (get_minor ());
802 /* Create synchronisation events */
805 const char *errmsg
= NULL
;
807 if (!(output_mutex
= get_ttyp ()->open_output_mutex (MAXIMUM_ALLOWED
)))
809 errmsg
= "open output mutex failed, %E";
812 if (!(input_mutex
= get_ttyp ()->open_input_mutex (MAXIMUM_ALLOWED
)))
814 errmsg
= "open input mutex failed, %E";
818 = get_ttyp ()->open_mutex (PIPE_SW_MUTEX
, MAXIMUM_ALLOWED
)))
820 errmsg
= "open pipe switch mutex failed, %E";
823 shared_name (buf
, INPUT_AVAILABLE_EVENT
, get_minor ());
824 if (!(input_available_event
= OpenEvent (MAXIMUM_ALLOWED
, TRUE
, buf
)))
826 errmsg
= "open input event failed, %E";
830 /* FIXME: Needs a method to eliminate tty races */
832 /* Create security attribute. Default permissions are 0620. */
833 security_descriptor sd
;
834 sd
.malloc (sizeof (SECURITY_DESCRIPTOR
));
835 RtlCreateSecurityDescriptor (sd
, SECURITY_DESCRIPTOR_REVISION
);
836 SECURITY_ATTRIBUTES sa
= { sizeof (SECURITY_ATTRIBUTES
), NULL
, TRUE
};
837 if (!create_object_sd_from_attribute (myself
->uid
, myself
->gid
,
838 S_IFCHR
| S_IRUSR
| S_IWUSR
| S_IWGRP
,
840 sa
.lpSecurityDescriptor
= (PSECURITY_DESCRIPTOR
) sd
;
841 acquire_output_mutex (mutex_timeout
);
842 inuse
= get_ttyp ()->create_inuse (&sa
);
843 get_ttyp ()->was_opened
= true;
844 release_output_mutex ();
847 if (!get_ttyp ()->from_master_nat () || !get_ttyp ()->from_master ()
848 || !get_ttyp ()->to_master_nat () || !get_ttyp ()->to_master ())
850 errmsg
= "pty handles have been closed";
855 /* Three case for duplicating the pipe handles:
856 - Either we're the master. In this case, just duplicate the handles.
857 - Or, we have the right to open the master process for handle duplication.
858 In this case, just duplicate the handles.
859 - Or, we have to ask the master process itself. In this case, send our
860 pid to the master process and check the reply. The reply contains
861 either the handles, or an error code which tells us why we didn't
863 if (myself
->pid
== get_ttyp ()->master_pid
)
865 /* This is the most common case, just calling openpty. */
866 termios_printf ("dup handles within myself.");
867 pty_owner
= GetCurrentProcess ();
871 pinfo
p (get_ttyp ()->master_pid
);
873 termios_printf ("*** couldn't find pty master");
876 pty_owner
= OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, p
->dwProcessId
);
878 termios_printf ("dup handles directly since I'm the owner");
883 if (!DuplicateHandle (pty_owner
, get_ttyp ()->from_master_nat (),
884 GetCurrentProcess (),
885 &from_master_nat_local
, 0, TRUE
,
886 DUPLICATE_SAME_ACCESS
))
888 termios_printf ("can't duplicate input from %u/%p, %E",
889 get_ttyp ()->master_pid
,
890 get_ttyp ()->from_master_nat ());
894 if (!DuplicateHandle (pty_owner
, get_ttyp ()->from_master (),
895 GetCurrentProcess (),
896 &from_master_local
, 0, TRUE
,
897 DUPLICATE_SAME_ACCESS
))
899 termios_printf ("can't duplicate input from %u/%p, %E",
900 get_ttyp ()->master_pid
,
901 get_ttyp ()->from_master ());
905 if (!DuplicateHandle (pty_owner
, get_ttyp ()->to_master_nat (),
906 GetCurrentProcess (),
907 &to_master_nat_local
, 0, TRUE
,
908 DUPLICATE_SAME_ACCESS
))
910 errmsg
= "can't duplicate output, %E";
913 if (!DuplicateHandle (pty_owner
, get_ttyp ()->to_master (),
914 GetCurrentProcess (),
915 &to_master_local
, 0, TRUE
,
916 DUPLICATE_SAME_ACCESS
))
918 errmsg
= "can't duplicate output for cygwin, %E";
921 if (pty_owner
!= GetCurrentProcess ())
922 CloseHandle (pty_owner
);
926 pipe_request req
= { GetCurrentProcessId () };
930 __small_sprintf (buf
, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
931 &cygheap
->installation_key
, get_minor ());
932 termios_printf ("dup handles via master control pipe %s", buf
);
933 if (!CallNamedPipe (buf
, &req
, sizeof req
, &repl
, sizeof repl
,
936 errmsg
= "can't call master, %E";
939 CloseHandle (repl
.to_slave_nat
); /* not used. */
940 CloseHandle (repl
.to_slave
); /* not used. */
941 from_master_nat_local
= repl
.from_master_nat
;
942 from_master_local
= repl
.from_master
;
943 to_master_nat_local
= repl
.to_master_nat
;
944 to_master_local
= repl
.to_master
;
945 if (!from_master_nat_local
|| !from_master_local
946 || !to_master_nat_local
|| !to_master_local
)
948 SetLastError (repl
.error
);
949 errmsg
= "error duplicating pipes, %E";
953 VerifyHandle (from_master_nat_local
);
954 VerifyHandle (from_master_local
);
955 VerifyHandle (to_master_nat_local
);
956 VerifyHandle (to_master_local
);
958 termios_printf ("duplicated from_master_nat %p->%p from pty_owner",
959 get_ttyp ()->from_master_nat (), from_master_nat_local
);
960 termios_printf ("duplicated from_master %p->%p from pty_owner",
961 get_ttyp ()->from_master (), from_master_local
);
962 termios_printf ("duplicated to_master_nat %p->%p from pty_owner",
963 get_ttyp ()->to_master_nat (), to_master_nat_local
);
964 termios_printf ("duplicated to_master %p->%p from pty_owner",
965 get_ttyp ()->to_master (), to_master_local
);
967 set_handle_nat (from_master_nat_local
);
968 set_handle (from_master_local
);
969 set_output_handle_nat (to_master_nat_local
);
970 set_output_handle (to_master_local
);
972 if (_major (myself
->ctty
) == DEV_CONS_MAJOR
973 && !(!pinfo (myself
->ppid
) && GetModuleHandle ("ConEmuHk64.dll")))
974 /* This process is supposed to be a master process which is
975 running on console. Invisible console will be created in
976 primary slave process to prevent overriding code page
977 of root console by setup_locale(). */
978 /* ... except for ConEmu cygwin-connector in which this
979 code does not work as expected because it calls Win32
980 API directly rather than cygwin read()/write(). Due to
981 this behaviour, protection based on attach_mutex does
983 get_ttyp ()->need_invisible_console
= true;
984 else if (_major (myself
->ctty
) != DEV_CONS_MAJOR
985 && (!get_ttyp ()->invisible_console_pid
986 || !pinfo (get_ttyp ()->invisible_console_pid
)))
987 /* Create a new invisible console for each pty to isolate
988 CTRL_C_EVENTs between ptys. */
989 get_ttyp ()->need_invisible_console
= true;
992 acquire_attach_mutex (mutex_timeout
);
993 fhandler_console::need_invisible ();
994 release_attach_mutex ();
1001 if (GetLastError () == ERROR_FILE_NOT_FOUND
)
1006 termios_printf (errmsg
);
1008 for (HANDLE
**h
= handles
; *h
; h
++)
1009 if (**h
&& **h
!= INVALID_HANDLE_VALUE
)
1015 fhandler_pty_slave::open_setup (int flags
)
1017 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
1018 myself
->set_ctty (this, flags
);
1019 report_tty_counts (this, "opened", "");
1020 return fhandler_base::open_setup (flags
);
1024 fhandler_pty_slave::cleanup ()
1026 /* This used to always call fhandler_pty_common::close when we were execing
1027 but that caused multiple closes of the handles associated with this pty.
1028 Since close_all_files is not called until after the cygwin process has
1029 synced or before a non-cygwin process has exited, it should be safe to
1030 just close this normally. cgf 2006-05-20 */
1031 report_tty_counts (this, "closed", "");
1032 fhandler_base::cleanup ();
1036 fhandler_pty_slave::close ()
1038 termios_printf ("closing last open %s handle", ttyname ());
1039 if (inuse
&& !CloseHandle (inuse
))
1040 termios_printf ("CloseHandle (inuse), %E");
1041 if (!ForceCloseHandle (input_available_event
))
1042 termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event
);
1043 if (!ForceCloseHandle (get_output_handle_nat ()))
1044 termios_printf ("CloseHandle (get_output_handle_nat ()<%p>), %E",
1045 get_output_handle_nat ());
1046 if (!ForceCloseHandle (get_handle_nat ()))
1047 termios_printf ("CloseHandle (get_handle_nat ()<%p>), %E",
1049 fhandler_pty_common::close ();
1050 if (!ForceCloseHandle (output_mutex
))
1051 termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex
);
1052 if (!get_ttyp ()->invisible_console_pid
&& myself
->ctty
== CTTY_RELEASED
)
1054 if (get_ttyp ()->invisible_console_pid
1055 && !pinfo (get_ttyp ()->invisible_console_pid
))
1056 get_ttyp ()->invisible_console_pid
= 0;
1061 fhandler_pty_slave::init (HANDLE h
, DWORD a
, mode_t
)
1065 a
&= GENERIC_READ
| GENERIC_WRITE
;
1066 if (a
== GENERIC_READ
)
1068 if (a
== GENERIC_WRITE
)
1070 if (a
== (GENERIC_READ
| GENERIC_WRITE
))
1073 int ret
= open_with_arch (flags
);
1075 if (ret
&& !cygwin_finished_initializing
&& !being_debugged ())
1077 /* This only occurs when called from dtable::init_std_file_from_handle
1078 We have been started from a non-Cygwin process. So we should become
1079 pty process group leader.
1080 TODO: Investigate how SIGTTIN should be handled with pure-windows
1082 pinfo
p (tc ()->getpgid ());
1083 /* We should only grab this when the process group owner for this
1084 pty is a non-cygwin process or we've been started directly
1085 from a non-Cygwin process with no Cygwin ancestry. */
1086 if (!p
|| ISSTATE (p
, PID_NOTCYGWIN
))
1088 termios_printf ("Setting process group leader to %d since %W(%d) is not a cygwin process",
1089 myself
->pgid
, p
->progname
, p
->pid
);
1090 tc ()->setpgid (myself
->pgid
);
1094 if (h
!= INVALID_HANDLE_VALUE
)
1095 CloseHandle (h
); /* Reopened by open */
1101 fhandler_pty_slave::set_switch_to_nat_pipe (void)
1107 myself
->exec_dwProcessId
= myself
->dwProcessId
; /* Set this as a marker
1109 and process_sigs() */
1110 bool stdin_is_ptys
= GetStdHandle (STD_INPUT_HANDLE
) == get_handle ();
1111 setup_for_non_cygwin_app (false, NULL
, stdin_is_ptys
);
1116 process_alive (DWORD pid
)
1118 /* This function is very similar to _pinfo::alive(), however, this
1119 can be used for non-cygwin process which is started from non-cygwin
1120 shell. In addition, this checks exit code as well. */
1123 HANDLE h
= OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, pid
);
1127 BOOL r
= GetExitCodeProcess (h
, &exit_code
);
1129 if (r
&& exit_code
== STILL_ACTIVE
)
1135 nat_pipe_owner_self (DWORD pid
)
1137 return (pid
== (myself
->exec_dwProcessId
?: myself
->dwProcessId
));
1140 /* This function is called from some pty slave functions. The purpose
1141 of this function is cleaning up the nat pipe state which is marked
1142 as active but actually not used anymore. This is needed only when
1143 non-cygwin process is not terminated cleanly. */
1145 fhandler_pty_slave::reset_switch_to_nat_pipe (void)
1149 if (WaitForSingleObject (h_gdb_inferior
, 0) == WAIT_TIMEOUT
)
1152 get_ttyp ()->wait_fwd ();
1156 CloseHandle (h_gdb_inferior
);
1157 h_gdb_inferior
= NULL
;
1158 mutex_timeout
= INFINITE
;
1161 if (get_ttyp ()->getpgid () == myself
->pgid
1162 && GetStdHandle (STD_INPUT_HANDLE
) == get_handle ()
1163 && get_ttyp ()->pty_input_state_eq (tty::to_nat
))
1165 WaitForSingleObject (input_mutex
, mutex_timeout
);
1166 acquire_attach_mutex (mutex_timeout
);
1167 transfer_input (tty::to_cyg
, get_handle_nat (), get_ttyp (),
1168 input_available_event
);
1169 release_attach_mutex ();
1170 ReleaseMutex (input_mutex
);
1172 if (get_ttyp ()->master_is_running_as_service
1173 && get_ttyp ()->pcon_activated
)
1174 /* If the master is running as service, re-attaching to
1175 the console of the parent process will fail.
1176 Therefore, never close pseudo console here. */
1178 bool need_restore_handles
= get_ttyp ()->pcon_activated
;
1179 WaitForSingleObject (pipe_sw_mutex
, INFINITE
);
1180 if (get_ttyp ()->pcon_activated
)
1181 close_pseudoconsole (get_ttyp ());
1183 hand_over_only (get_ttyp ());
1184 ReleaseMutex (pipe_sw_mutex
);
1185 if (need_restore_handles
)
1187 pinfo
p (get_ttyp ()->master_pid
);
1189 OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, p
->dwProcessId
);
1192 CloseHandle (get_handle_nat ());
1193 DuplicateHandle (pty_owner
,
1194 get_ttyp ()->from_master_nat (),
1195 GetCurrentProcess (), &get_handle_nat (),
1196 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1197 CloseHandle (get_output_handle_nat ());
1198 DuplicateHandle (pty_owner
,
1199 get_ttyp ()->to_master_nat (),
1200 GetCurrentProcess (),
1201 &get_output_handle_nat (),
1202 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1203 CloseHandle (pty_owner
);
1207 char pipe
[MAX_PATH
];
1208 __small_sprintf (pipe
,
1209 "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
1210 &cygheap
->installation_key
, get_minor ());
1211 pipe_request req
= { GetCurrentProcessId () };
1214 if (!CallNamedPipe (pipe
, &req
, sizeof req
,
1215 &repl
, sizeof repl
, &len
, 500))
1216 return; /* What can we do? */
1217 CloseHandle (repl
.from_master
); /* not used. */
1218 CloseHandle (repl
.to_master
); /* not used. */
1219 CloseHandle (repl
.to_slave_nat
); /* not used. */
1220 CloseHandle (repl
.to_slave
); /* not used. */
1221 CloseHandle (get_handle_nat ());
1222 set_handle_nat (repl
.from_master_nat
);
1223 CloseHandle (get_output_handle_nat ());
1224 set_output_handle_nat (repl
.to_master_nat
);
1227 myself
->exec_dwProcessId
= 0;
1234 if (get_ttyp ()->pcon_start
) /* Pseudo console initialization is on going */
1236 DWORD wait_ret
= WaitForSingleObject (pipe_sw_mutex
, mutex_timeout
);
1237 if (wait_ret
== WAIT_TIMEOUT
)
1239 if (!nat_pipe_owner_self (get_ttyp ()->nat_pipe_owner_pid
)
1240 && process_alive (get_ttyp ()->nat_pipe_owner_pid
))
1242 /* There is a process which owns nat pipe. */
1243 ReleaseMutex (pipe_sw_mutex
);
1246 /* Clean up nat pipe state */
1247 get_ttyp ()->pty_input_state
= tty::to_cyg
;
1248 get_ttyp ()->nat_pipe_owner_pid
= 0;
1249 get_ttyp ()->switch_to_nat_pipe
= false;
1250 get_ttyp ()->pcon_activated
= false;
1251 ReleaseMutex (pipe_sw_mutex
);
1255 fhandler_pty_slave::write (const void *ptr
, size_t len
)
1257 ssize_t towrite
= len
;
1259 bg_check_types bg
= bg_check (SIGTTOU
);
1261 return (ssize_t
) bg
;
1263 termios_printf ("pty%d, write(%p, %lu)", get_minor (), ptr
, len
);
1265 push_process_state
process_state (PID_TTYOU
);
1267 acquire_output_mutex (mutex_timeout
);
1268 if (!process_opost_output (get_output_handle (), ptr
, towrite
, false,
1269 get_ttyp (), is_nonblocking ()))
1271 DWORD err
= GetLastError ();
1272 termios_printf ("WriteFile failed, %E");
1276 err
= ERROR_IO_DEVICE
;
1279 __seterrno_from_win_error (err
);
1283 release_output_mutex ();
1288 /* This function is called from some slave pty reading functions
1289 to switch active pipe to cygwin pipe (not nat pipe) temporarily
1290 even though there is another process which owns nat pipe. This
1291 is needed if cygwin process reads input while another non-cygwin
1292 process is running at the same time.
1293 (e.g. Something like "cat | non-cygwin-app") */
1295 fhandler_pty_slave::mask_switch_to_nat_pipe (bool mask
, bool xfer
)
1297 char name
[MAX_PATH
];
1298 shared_name (name
, TTY_SLAVE_READING
, get_minor ());
1299 HANDLE masked
= OpenEvent (READ_CONTROL
, FALSE
, name
);
1300 CloseHandle (masked
);
1302 WaitForSingleObject (input_mutex
, mutex_timeout
);
1305 if (InterlockedIncrement (&num_reader
) == 1)
1306 slave_reading
= CreateEvent (&sec_none_nih
, TRUE
, FALSE
, name
);
1308 else if (InterlockedDecrement (&num_reader
) == 0)
1309 CloseHandle (slave_reading
);
1311 if (!!masked
!= mask
&& xfer
&& get_ttyp ()->switch_to_nat_pipe
)
1313 if (mask
&& get_ttyp ()->pty_input_state_eq (tty::to_nat
))
1315 acquire_attach_mutex (mutex_timeout
);
1316 transfer_input (tty::to_cyg
, get_handle_nat (), get_ttyp (),
1317 input_available_event
);
1318 release_attach_mutex ();
1320 else if (!mask
&& get_ttyp ()->pty_input_state_eq (tty::to_cyg
))
1322 acquire_attach_mutex (mutex_timeout
);
1323 transfer_input (tty::to_nat
, get_handle (), get_ttyp (),
1324 input_available_event
);
1325 release_attach_mutex ();
1328 ReleaseMutex (input_mutex
);
1331 /* Return true when the non-cygwin app is reading the input. */
1333 fhandler_pty_common::to_be_read_from_nat_pipe (void)
1335 if (!get_ttyp ()->switch_to_nat_pipe
)
1338 char name
[MAX_PATH
];
1339 shared_name (name
, TTY_SLAVE_READING
, get_minor ());
1340 HANDLE masked
= OpenEvent (READ_CONTROL
, FALSE
, name
);
1341 CloseHandle (masked
);
1343 if (masked
) /* The foreground process is cygwin process */
1346 if (!pinfo (get_ttyp ()->getpgid ()))
1347 /* GDB may set invalid process group for non-cygwin process. */
1350 return get_ttyp ()->nat_fg (get_ttyp ()->getpgid ());
1354 fhandler_pty_slave::read (void *ptr
, size_t& len
)
1356 ssize_t totalread
= 0;
1358 int vtime
= 0; /* Initialized to prevent -Wuninitialized warning */
1360 DWORD bytes_in_pipe
;
1361 char buf
[INP_BUFFER_SIZE
];
1363 char *ptr0
= (char *) ptr
;
1365 bg_check_types bg
= bg_check (SIGTTIN
);
1372 termios_printf ("read(%p, %lu) handle %p", ptr
, len
, get_handle ());
1374 push_process_state
process_state (PID_TTYIN
);
1376 if (ptr
) /* Indicating not tcflush(). */
1377 mask_switch_to_nat_pipe (true, true);
1379 if (is_nonblocking () || !ptr
) /* Indicating tcflush(). */
1381 else if ((get_ttyp ()->ti
.c_lflag
& ICANON
))
1382 time_to_wait
= INFINITE
;
1385 vmin
= get_ttyp ()->ti
.c_cc
[VMIN
];
1386 if (vmin
> INP_BUFFER_SIZE
)
1387 vmin
= INP_BUFFER_SIZE
;
1388 vtime
= get_ttyp ()->ti
.c_cc
[VTIME
];
1393 if (!vmin
&& !vtime
)
1396 time_to_wait
= !vtime
? INFINITE
: 100 * vtime
;
1402 switch (cygwait (input_available_event
, time_to_wait
))
1409 termios_printf ("wait catched signal");
1410 set_sig_errno (EINTR
);
1414 process_state
.pop ();
1415 pthread::static_cancel_self ();
1418 termios_printf ("wait timed out, time_to_wait %u", time_to_wait
);
1419 /* No error condition when called from tcflush. */
1420 if (!totalread
&& ptr
)
1422 set_sig_errno (EAGAIN
);
1427 termios_printf ("wait for input event failed, %E");
1435 /* Now that we know that input is available we have to grab the
1437 switch (cygwait (input_mutex
, 1000))
1440 case WAIT_ABANDONED_0
:
1445 termios_printf ("wait for mutex caught signal");
1446 set_sig_errno (EINTR
);
1450 process_state
.pop ();
1451 pthread::static_cancel_self ();
1454 termios_printf ("failed to acquire input mutex after input event "
1456 /* If we have a timeout, we can simply handle this failure to
1457 grab the mutex as an EAGAIN situation. Otherwise, if this
1458 is an infinitely blocking read, restart the loop. */
1459 if (time_to_wait
!= INFINITE
)
1463 set_sig_errno (EAGAIN
);
1470 termios_printf ("wait for input mutex failed, %E");
1478 if (!IsEventSignalled (input_available_event
))
1479 { /* Maybe another thread has processed input. */
1480 ReleaseMutex (input_mutex
);
1484 if (!bytes_available (bytes_in_pipe
))
1486 ReleaseMutex (input_mutex
);
1492 if (ptr
&& !bytes_in_pipe
&& !vmin
&& !time_to_wait
)
1494 ReleaseMutex (input_mutex
);
1495 mask_switch_to_nat_pipe (false, false);
1496 len
= (size_t) bytes_in_pipe
;
1500 readlen
= bytes_in_pipe
? MIN (len
, sizeof (buf
)) : 0;
1501 if (get_ttyp ()->ti
.c_lflag
& ICANON
&& ptr
)
1502 readlen
= MIN (bytes_in_pipe
, readlen
);
1505 /* Why on earth is the read length reduced to vmin, even if more bytes
1506 are available *and* len is bigger *and* the local buf is big enough?
1507 Disable this code for now, it looks like a remnant of old. */
1508 if (ptr
&& vmin
&& readlen
> (unsigned) vmin
)
1515 termios_printf ("reading %lu bytes (vtime %d)", readlen
, vtime
);
1516 if (!ReadFile (get_handle (), buf
, readlen
, &n
, NULL
))
1518 termios_printf ("read failed, %E");
1519 ReleaseMutex (input_mutex
);
1526 /* MSDN states that 5th prameter can be used to determine total
1527 number of bytes in pipe, but for some reason this number doesn't
1528 change after successful read. So we have to peek into the pipe
1529 again to see if input is still available */
1530 if (!bytes_available (bytes_in_pipe
))
1532 ReleaseMutex (input_mutex
);
1539 if (!(!ptr
&& len
== UINT_MAX
)) /* not tcflush() */
1544 memcpy (ptr
, buf
, n
);
1545 ptr
= (char *) ptr
+ n
;
1552 ResetEvent (input_available_event
);
1554 ReleaseMutex (input_mutex
);
1563 if (get_ttyp ()->read_retval
< 0) // read error
1565 set_errno (-get_ttyp ()->read_retval
);
1569 if (get_ttyp ()->read_retval
== 0) //EOF
1571 termios_printf ("saw EOF");
1574 if (get_ttyp ()->ti
.c_lflag
& ICANON
|| is_nonblocking ())
1576 if (vmin
&& totalread
>= vmin
)
1579 /* vmin == 0 && vtime == 0:
1580 * we've already read all input, if any, so return immediately
1581 * vmin == 0 && vtime > 0:
1582 * we've waited for input 10*vtime ms in WFSO(input_available_event),
1583 * no matter whether any input arrived, we shouldn't wait any longer,
1584 * so return immediately
1585 * vmin > 0 && vtime == 0:
1586 * here, totalread < vmin, so continue waiting until more data
1588 * vmin > 0 && vtime > 0:
1589 * similar to the previous here, totalread < vmin, and timer
1590 * hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT,
1591 * so "restart timer" and wait until more data arrive
1598 termios_printf ("%d = read(%p, %lu)", totalread
, ptr
, len
);
1599 len
= (size_t) totalread
;
1601 { /* Not tcflush() */
1602 bool saw_eol
= totalread
> 0 && strchr ("\r\n", ptr0
[totalread
-1]);
1603 mask_switch_to_nat_pipe (false, saw_eol
|| len
== 0);
1608 fhandler_pty_slave::dup (fhandler_base
*child
, int flags
)
1610 /* This code was added in Oct 2001 for some undisclosed reason.
1611 However, setting the controlling tty on a dup causes rxvt to
1612 hang when the parent does a dup since the controlling pgid changes.
1613 Specifically testing for CTTY_RELEASED (ctty has been setsid'ed)
1614 works around this problem. However, it's difficult to see scenarios
1615 in which you have a dup'able fd, no controlling tty, and not having
1616 run setsid. So, we might want to consider getting rid of the
1617 set_ctty in tty-like dup methods entirely at some point */
1618 if (myself
->ctty
!= CTTY_RELEASED
)
1619 myself
->set_ctty (this, flags
);
1620 report_tty_counts (child
, "duped slave", "");
1625 fhandler_pty_master::dup (fhandler_base
*child
, int)
1627 report_tty_counts (child
, "duped master", "");
1632 fhandler_pty_slave::tcgetattr (struct termios
*t
)
1634 *t
= get_ttyp ()->ti
;
1636 /* Workaround for rlwrap */
1637 cygheap_fdenum
cfd (false);
1638 while (cfd
.next () >= 0)
1639 if (cfd
->get_major () == DEV_PTYM_MAJOR
1640 && cfd
->get_minor () == get_minor ())
1642 if (get_ttyp ()->pcon_start
)
1643 t
->c_lflag
&= ~(ICANON
| ECHO
);
1644 if (get_ttyp ()->pcon_activated
)
1645 t
->c_iflag
&= ~ICRNL
;
1652 fhandler_pty_slave::tcsetattr (int, const struct termios
*t
)
1654 acquire_output_mutex (mutex_timeout
);
1655 get_ttyp ()->ti
= *t
;
1656 release_output_mutex ();
1661 fhandler_pty_slave::tcflush (int queue
)
1665 termios_printf ("tcflush(%d) handle %p", queue
, get_handle ());
1667 if (queue
== TCIFLUSH
|| queue
== TCIOFLUSH
)
1669 size_t len
= UINT_MAX
;
1671 ret
= ((int) len
) >= 0 ? 0 : -1;
1673 if (queue
== TCOFLUSH
|| queue
== TCIOFLUSH
)
1675 /* do nothing for now. */
1678 termios_printf ("%d=tcflush(%d)", ret
, queue
);
1683 fhandler_pty_slave::ioctl (unsigned int cmd
, void *arg
)
1685 termios_printf ("ioctl (%x)", cmd
);
1686 int res
= fhandler_termios::ioctl (cmd
, arg
);
1690 if (myself
->pgid
&& get_ttyp ()->getpgid () != myself
->pgid
1691 && (unsigned) myself
->ctty
== FHDEV (DEV_PTYS_MAJOR
, get_minor ())
1692 && (get_ttyp ()->ti
.c_lflag
& TOSTOP
))
1694 /* background process */
1695 termios_printf ("bg ioctl pgid %d, tpgid %d, %s", myself
->pgid
,
1696 get_ttyp ()->getpgid (), myctty ());
1708 pid_t pid
= this->tcgetpgrp ();
1713 *((pid_t
*) arg
) = pid
;
1719 retval
= this->tcsetpgrp ((pid_t
) (intptr_t) arg
);
1724 if (!bytes_available (n
))
1731 *(int *) arg
= (int) n
;
1737 return fhandler_base::ioctl (cmd
, arg
);
1740 acquire_output_mutex (mutex_timeout
);
1742 get_ttyp ()->cmd
= cmd
;
1743 get_ttyp ()->ioctl_retval
= 0;
1747 get_ttyp ()->arg
.winsize
= get_ttyp ()->winsize
;
1748 *(struct winsize
*) arg
= get_ttyp ()->arg
.winsize
;
1749 get_ttyp ()->winsize
= get_ttyp ()->arg
.winsize
;
1752 if (get_ttyp ()->winsize
.ws_row
!= ((struct winsize
*) arg
)->ws_row
1753 || get_ttyp ()->winsize
.ws_col
!= ((struct winsize
*) arg
)->ws_col
1754 || get_ttyp ()->winsize
.ws_ypixel
!= ((struct winsize
*) arg
)->ws_ypixel
1755 || get_ttyp ()->winsize
.ws_xpixel
!= ((struct winsize
*) arg
)->ws_xpixel
1758 if (get_ttyp ()->pcon_activated
&& get_ttyp ()->nat_pipe_owner_pid
)
1759 resize_pseudo_console ((struct winsize
*) arg
);
1760 get_ttyp ()->arg
.winsize
= *(struct winsize
*) arg
;
1761 get_ttyp ()->winsize
= *(struct winsize
*) arg
;
1762 get_ttyp ()->kill_pgrp (SIGWINCH
);
1767 release_output_mutex ();
1768 retval
= get_ttyp ()->ioctl_retval
;
1771 set_errno (-retval
);
1776 termios_printf ("%d = ioctl(%x)", retval
, cmd
);
1781 fhandler_pty_slave::fstat (struct stat
*st
)
1783 fhandler_termios::fstat (st
);
1785 bool to_close
= false;
1786 if (!input_available_event
)
1789 shared_name (buf
, INPUT_AVAILABLE_EVENT
, get_minor ());
1790 input_available_event
= OpenEvent (READ_CONTROL
, TRUE
, buf
);
1791 if (input_available_event
)
1794 st
->st_mode
= S_IFCHR
;
1795 if (!input_available_event
1796 || get_object_attribute (input_available_event
, &st
->st_uid
, &st
->st_gid
,
1799 /* If we can't access the ACL, or if the tty doesn't actually exist,
1800 then fake uid and gid to strict, system-like values. */
1801 st
->st_mode
= S_IFCHR
| S_IRUSR
| S_IWUSR
;
1806 CloseHandle (input_available_event
);
1811 fhandler_pty_slave::facl (int cmd
, int nentries
, aclent_t
*aclbufp
)
1814 bool to_close
= false;
1815 security_descriptor sd
;
1816 mode_t attr
= S_IFCHR
;
1821 if (!aclsort (nentries
, 0, aclbufp
))
1822 set_errno (ENOTSUP
);
1832 if (!input_available_event
)
1835 shared_name (buf
, INPUT_AVAILABLE_EVENT
, get_minor ());
1836 input_available_event
= OpenEvent (READ_CONTROL
, TRUE
, buf
);
1837 if (input_available_event
)
1840 if (!input_available_event
1841 || get_object_sd (input_available_event
, sd
))
1843 res
= get_posix_access (NULL
, attr
, NULL
, NULL
, aclbufp
, nentries
);
1844 if (aclbufp
&& res
== MIN_ACL_ENTRIES
)
1846 aclbufp
[0].a_perm
= S_IROTH
| S_IWOTH
;
1847 aclbufp
[0].a_id
= 18;
1848 aclbufp
[1].a_id
= 544;
1853 res
= get_posix_access (sd
, attr
, NULL
, NULL
, aclbufp
, nentries
);
1855 res
= get_posix_access (sd
, attr
, NULL
, NULL
, NULL
, 0);
1862 CloseHandle (input_available_event
);
1866 /* Helper function for fchmod and fchown, which just opens all handles
1867 and signals success via bool return. */
1869 fhandler_pty_slave::fch_open_handles (bool chown
)
1872 DWORD write_access
= WRITE_DAC
| (chown
? WRITE_OWNER
: 0);
1874 _tc
= cygwin_shared
->tty
[get_minor ()];
1875 shared_name (buf
, INPUT_AVAILABLE_EVENT
, get_minor ());
1876 input_available_event
= OpenEvent (READ_CONTROL
| write_access
,
1878 output_mutex
= get_ttyp ()->open_output_mutex (write_access
);
1879 input_mutex
= get_ttyp ()->open_input_mutex (write_access
);
1880 pipe_sw_mutex
= get_ttyp ()->open_mutex (PIPE_SW_MUTEX
, write_access
);
1881 inuse
= get_ttyp ()->open_inuse (write_access
);
1882 if (!input_available_event
|| !output_mutex
|| !input_mutex
|| !inuse
)
1890 /* Helper function for fchmod and fchown, which sets the new security
1891 descriptor on all objects representing the pty. */
1893 fhandler_pty_slave::fch_set_sd (security_descriptor
&sd
, bool chown
)
1895 security_descriptor sd_old
;
1897 get_object_sd (input_available_event
, sd_old
);
1898 if (!set_object_sd (input_available_event
, sd
, chown
)
1899 && !set_object_sd (output_mutex
, sd
, chown
)
1900 && !set_object_sd (input_mutex
, sd
, chown
)
1901 && !set_object_sd (inuse
, sd
, chown
))
1903 set_object_sd (input_available_event
, sd_old
, chown
);
1904 set_object_sd (output_mutex
, sd_old
, chown
);
1905 set_object_sd (input_mutex
, sd_old
, chown
);
1906 set_object_sd (inuse
, sd_old
, chown
);
1910 /* Helper function for fchmod and fchown, which closes all object handles in
1913 fhandler_pty_slave::fch_close_handles ()
1915 close_maybe (input_available_event
);
1916 close_maybe (output_mutex
);
1917 close_maybe (input_mutex
);
1918 close_maybe (inuse
);
1922 fhandler_pty_slave::fchmod (mode_t mode
)
1925 bool to_close
= false;
1926 security_descriptor sd
;
1929 mode_t orig_mode
= S_IFCHR
;
1931 if (!input_available_event
)
1934 if (!fch_open_handles (false))
1937 sd
.malloc (sizeof (SECURITY_DESCRIPTOR
));
1938 RtlCreateSecurityDescriptor (sd
, SECURITY_DESCRIPTOR_REVISION
);
1939 if (!get_object_attribute (input_available_event
, &uid
, &gid
, orig_mode
)
1940 && !create_object_sd_from_attribute (uid
, gid
, S_IFCHR
| mode
, sd
))
1941 ret
= fch_set_sd (sd
, false);
1944 fch_close_handles ();
1949 fhandler_pty_slave::fchown (uid_t uid
, gid_t gid
)
1952 bool to_close
= false;
1953 security_descriptor sd
;
1956 mode_t mode
= S_IFCHR
;
1958 if (uid
== ILLEGAL_UID
&& gid
== ILLEGAL_GID
)
1960 if (!input_available_event
)
1963 if (!fch_open_handles (true))
1966 sd
.malloc (sizeof (SECURITY_DESCRIPTOR
));
1967 RtlCreateSecurityDescriptor (sd
, SECURITY_DESCRIPTOR_REVISION
);
1968 if (!get_object_attribute (input_available_event
, &o_uid
, &o_gid
, mode
))
1970 if (uid
== ILLEGAL_UID
)
1972 if (gid
== ILLEGAL_GID
)
1974 if (uid
== o_uid
&& gid
== o_gid
)
1976 else if (!create_object_sd_from_attribute (uid
, gid
, mode
, sd
))
1977 ret
= fch_set_sd (sd
, true);
1981 fch_close_handles ();
1985 /*******************************************************
1988 fhandler_pty_master::fhandler_pty_master (int unit
, dev_t via
)
1989 : fhandler_pty_common (), pktmode (0), master_ctl (NULL
),
1990 master_thread (NULL
), from_master_nat (NULL
), to_master_nat (NULL
),
1991 from_slave_nat (NULL
), to_slave_nat (NULL
), echo_r (NULL
), echo_w (NULL
),
1992 dwProcessId (0), to_master (NULL
), from_master (NULL
),
1993 master_fwd_thread (NULL
)
1995 dev_referred_via
= via
;
1997 dev ().parse (DEV_PTYM_MAJOR
, unit
);
1998 set_name ("/dev/ptmx");
2002 fhandler_pty_master::open (int flags
, mode_t
)
2007 dwProcessId
= GetCurrentProcessId ();
2012 fhandler_pty_master::open_setup (int flags
)
2014 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
2015 char buf
[sizeof ("opened pty master for ptyNNNNNNNNNNN")];
2016 __small_sprintf (buf
, "opened pty master for pty%d", get_minor ());
2017 report_tty_counts (this, buf
, "");
2018 return fhandler_base::open_setup (flags
);
2022 fhandler_pty_common::lseek (off_t
, int)
2029 fhandler_pty_common::close ()
2031 termios_printf ("pty%d <%p,%p> closing",
2032 get_minor (), get_handle (), get_output_handle ());
2033 if (!ForceCloseHandle (input_mutex
))
2034 termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex
);
2035 if (!ForceCloseHandle (pipe_sw_mutex
))
2036 termios_printf ("CloseHandle (pipe_sw_mutex<%p>), %E", pipe_sw_mutex
);
2037 if (!ForceCloseHandle1 (get_handle (), from_pty
))
2038 termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ());
2039 if (!ForceCloseHandle1 (get_output_handle (), to_pty
))
2040 termios_printf ("CloseHandle (get_output_handle ()<%p>), %E",
2041 get_output_handle ());
2047 fhandler_pty_common::resize_pseudo_console (struct winsize
*ws
)
2050 size
.X
= ws
->ws_col
;
2051 size
.Y
= ws
->ws_row
;
2052 HPCON_INTERNAL hpcon_local
;
2054 OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, get_ttyp ()->nat_pipe_owner_pid
);
2055 DuplicateHandle (pcon_owner
, get_ttyp ()->h_pcon_write_pipe
,
2056 GetCurrentProcess (), &hpcon_local
.hWritePipe
,
2057 0, FALSE
, DUPLICATE_SAME_ACCESS
);
2058 acquire_attach_mutex (mutex_timeout
);
2059 ResizePseudoConsole ((HPCON
) &hpcon_local
, size
);
2060 release_attach_mutex ();
2061 CloseHandle (pcon_owner
);
2062 CloseHandle (hpcon_local
.hWritePipe
);
2066 fhandler_pty_master::cleanup ()
2068 report_tty_counts (this, "closing master", "");
2070 from_master_nat
= from_master
=
2071 to_master_nat
= to_master
= from_slave_nat
= to_slave_nat
= NULL
;
2072 fhandler_base::cleanup ();
2076 fhandler_pty_master::close ()
2078 OBJECT_BASIC_INFORMATION obi
;
2081 termios_printf ("closing from_master_nat(%p)/from_master(%p)/to_master_nat(%p)/to_master(%p) since we own them(%u)",
2082 from_master_nat
, from_master
,
2083 to_master_nat
, to_master
, dwProcessId
);
2084 if (cygwin_finished_initializing
)
2086 if (master_ctl
&& get_ttyp ()->master_pid
== myself
->pid
)
2089 pipe_request req
= { (DWORD
) -1 };
2093 __small_sprintf (buf
, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
2094 &cygheap
->installation_key
, get_minor ());
2095 acquire_output_mutex (mutex_timeout
);
2098 CallNamedPipe (buf
, &req
, sizeof req
, &repl
, sizeof repl
, &len
,
2100 CloseHandle (master_ctl
);
2101 master_thread
->detach ();
2102 get_ttyp ()->set_master_ctl_closed ();
2105 release_output_mutex ();
2106 get_ttyp ()->stop_fwd_thread
= true;
2107 WriteFile (to_master_nat
, "", 0, &len
, NULL
);
2108 master_fwd_thread
->detach ();
2111 SetEvent (helper_goodbye
);
2112 WaitForSingleObject (helper_h_process
, INFINITE
);
2113 CloseHandle (helper_h_process
);
2114 CloseHandle (helper_goodbye
);
2115 helper_h_process
= 0;
2116 helper_goodbye
= NULL
;
2121 /* Check if the last master handle has been closed. If so, set
2122 input_available_event to wake up potentially waiting slaves. */
2123 acquire_output_mutex (mutex_timeout
);
2124 status
= NtQueryObject (get_output_handle (), ObjectBasicInformation
,
2125 &obi
, sizeof obi
, NULL
);
2126 fhandler_pty_common::close ();
2127 release_output_mutex ();
2128 if (!ForceCloseHandle (output_mutex
))
2129 termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex
);
2130 if (!NT_SUCCESS (status
))
2131 debug_printf ("NtQueryObject: %y", status
);
2132 else if (obi
.HandleCount
== 1)
2134 termios_printf ("Closing last master of pty%d", get_minor ());
2135 if (get_ttyp ()->getsid () > 0)
2136 kill (get_ttyp ()->getsid (), SIGHUP
);
2137 SetEvent (input_available_event
);
2140 if (!ForceCloseHandle (from_master_nat
))
2141 termios_printf ("error closing from_master_nat %p, %E", from_master_nat
);
2142 if (!ForceCloseHandle (to_master_nat
))
2143 termios_printf ("error closing to_master_nat %p, %E", to_master_nat
);
2144 from_master_nat
= to_master_nat
= NULL
;
2145 if (!ForceCloseHandle (from_slave_nat
))
2146 termios_printf ("error closing from_slave_nat %p, %E", from_slave_nat
);
2147 from_slave_nat
= NULL
;
2148 if (!ForceCloseHandle (to_master
))
2149 termios_printf ("error closing to_master %p, %E", to_master
);
2151 ForceCloseHandle (echo_r
);
2152 ForceCloseHandle (echo_w
);
2153 echo_r
= echo_w
= NULL
;
2155 ForceCloseHandle (to_slave_nat
);
2156 to_slave_nat
= NULL
;
2158 if (have_execed
|| get_ttyp ()->master_pid
!= myself
->pid
)
2159 termios_printf ("not clearing: %d, master_pid %d",
2160 have_execed
, get_ttyp ()->master_pid
);
2161 if (!ForceCloseHandle (input_available_event
))
2162 termios_printf ("CloseHandle (input_available_event<%p>), %E",
2163 input_available_event
);
2165 /* The from_master must be closed last so that the same pty is not
2166 allocated before cleaning up the other corresponding instances. */
2167 if (!ForceCloseHandle (from_master
))
2168 termios_printf ("error closing from_master %p, %E", from_master
);
2175 fhandler_pty_master::write (const void *ptr
, size_t len
)
2178 char *p
= (char *) ptr
;
2179 termios
&ti
= tc ()->ti
;
2181 bg_check_types bg
= bg_check (SIGTTOU
);
2183 return (ssize_t
) bg
;
2185 push_process_state
process_state (PID_TTYOU
);
2187 if (get_ttyp ()->pcon_start
)
2188 { /* Reaches here when pseudo console initialization is on going. */
2189 /* Pseudo condole support uses "CSI6n" to get cursor position.
2190 If the reply for "CSI6n" is divided into multiple writes,
2191 pseudo console sometimes does not recognize it. Therefore,
2192 put them together into wpbuf and write all at once. */
2193 static const int wpbuf_len
= strlen ("\033[32768;32868R");
2194 static char wpbuf
[wpbuf_len
];
2195 static int ixput
= 0;
2196 static int state
= 0;
2199 WaitForSingleObject (input_mutex
, mutex_timeout
);
2200 for (size_t i
= 0; i
< len
; i
++)
2205 line_edit (wpbuf
, ixput
, ti
, &ret
);
2211 if (ixput
< wpbuf_len
)
2212 wpbuf
[ixput
++] = p
[i
];
2215 if (!get_ttyp ()->req_xfer_input
)
2216 WriteFile (to_slave_nat
, wpbuf
, ixput
, &n
, NULL
);
2218 wpbuf
[ixput
++] = p
[i
];
2222 line_edit (p
+ i
, 1, ti
, &ret
);
2223 if (state
== 1 && p
[i
] == 'R')
2228 /* req_xfer_input is true if "ESC[6n" was sent just for
2229 triggering transfer_input() in master. In this case,
2230 the responce sequence should not be written. */
2231 if (!get_ttyp ()->req_xfer_input
)
2232 WriteFile (to_slave_nat
, wpbuf
, ixput
, &n
, NULL
);
2235 get_ttyp ()->req_xfer_input
= false;
2236 get_ttyp ()->pcon_start
= false;
2238 ReleaseMutex (input_mutex
);
2240 if (!get_ttyp ()->pcon_start
)
2241 { /* Pseudo console initialization has been done in above code. */
2242 pinfo
pp (get_ttyp ()->pcon_start_pid
);
2243 if (get_ttyp ()->switch_to_nat_pipe
2244 && get_ttyp ()->pty_input_state_eq (tty::to_cyg
))
2246 /* This accept_input() call is needed in order to transfer input
2247 which is not accepted yet to non-cygwin pipe. */
2248 WaitForSingleObject (input_mutex
, mutex_timeout
);
2249 if (get_readahead_valid ())
2251 acquire_attach_mutex (mutex_timeout
);
2252 fhandler_pty_slave::transfer_input (tty::to_nat
, from_master
,
2254 input_available_event
);
2255 release_attach_mutex ();
2256 ReleaseMutex (input_mutex
);
2258 get_ttyp ()->pcon_start_pid
= 0;
2264 /* Write terminal input to to_slave_nat pipe instead of output_handle
2265 if current application is native console application. */
2266 WaitForSingleObject (input_mutex
, mutex_timeout
);
2267 if (to_be_read_from_nat_pipe () && get_ttyp ()->pcon_activated
2268 && get_ttyp ()->pty_input_state
== tty::to_nat
)
2269 { /* Reaches here when non-cygwin app is foreground and pseudo console
2272 char *buf
= (char *) ptr
;
2274 if (get_ttyp ()->term_code_page
!= CP_UTF8
)
2276 static mbstate_t mbp
;
2279 convert_mb_str (CP_UTF8
, buf
, &nlen
,
2280 get_ttyp ()->term_code_page
, (const char *) ptr
, len
,
2284 for (size_t i
= 0; i
< nlen
; i
++)
2286 process_sig_state r
= process_sigs (buf
[i
], get_ttyp (), this);
2287 if (r
== done_with_debugger
)
2289 for (size_t j
= i
; j
< nlen
- 1; j
++)
2290 buf
[j
] = buf
[j
+ 1];
2294 process_stop_start (buf
[i
], get_ttyp ());
2298 WriteFile (to_slave_nat
, buf
, nlen
, &n
, NULL
);
2299 ReleaseMutex (input_mutex
);
2304 /* The code path reaches here when pseudo console is not activated
2305 or cygwin process is foreground even though pseudo console is
2308 /* This input transfer is needed when cygwin-app which is started from
2309 non-cygwin app is terminated if pseudo console is disabled. */
2310 if (to_be_read_from_nat_pipe () && !get_ttyp ()->pcon_activated
2311 && get_ttyp ()->pty_input_state
== tty::to_cyg
)
2313 acquire_attach_mutex (mutex_timeout
);
2314 fhandler_pty_slave::transfer_input (tty::to_nat
, from_master
,
2315 get_ttyp (), input_available_event
);
2316 release_attach_mutex ();
2319 line_edit_status status
= line_edit (p
, len
, ti
, &ret
);
2320 ReleaseMutex (input_mutex
);
2322 if (status
> line_edit_signalled
&& status
!= line_edit_pipe_full
)
2328 fhandler_pty_master::read (void *ptr
, size_t& len
)
2330 bg_check_types bg
= bg_check (SIGTTIN
);
2336 push_process_state
process_state (PID_TTYIN
);
2337 len
= (size_t) process_slave_output ((char *) ptr
, len
, pktmode
);
2341 fhandler_pty_master::tcgetattr (struct termios
*t
)
2343 *t
= cygwin_shared
->tty
[get_minor ()]->ti
;
2344 /* Workaround for rlwrap v0.40 or later */
2345 if (get_ttyp ()->pcon_start
)
2346 t
->c_lflag
&= ~(ICANON
| ECHO
);
2347 if (get_ttyp ()->pcon_activated
)
2348 t
->c_iflag
&= ~ICRNL
;
2353 fhandler_pty_master::tcsetattr (int, const struct termios
*t
)
2355 cygwin_shared
->tty
[get_minor ()]->ti
= *t
;
2360 fhandler_pty_master::tcflush (int queue
)
2364 termios_printf ("tcflush(%d) handle %p", queue
, get_handle ());
2366 if (queue
== TCIFLUSH
|| queue
== TCIOFLUSH
)
2367 ret
= process_slave_output (NULL
, OUT_BUFFER_SIZE
, 0);
2368 if (queue
== TCOFLUSH
|| queue
== TCIOFLUSH
)
2370 /* do nothing for now. */
2373 termios_printf ("%d=tcflush(%d)", ret
, queue
);
2378 fhandler_pty_master::ioctl (unsigned int cmd
, void *arg
)
2380 int res
= fhandler_termios::ioctl (cmd
, arg
);
2387 pktmode
= *(int *) arg
;
2390 *(struct winsize
*) arg
= get_ttyp ()->winsize
;
2393 if (get_ttyp ()->winsize
.ws_row
!= ((struct winsize
*) arg
)->ws_row
2394 || get_ttyp ()->winsize
.ws_col
!= ((struct winsize
*) arg
)->ws_col
2395 || get_ttyp ()->winsize
.ws_ypixel
!= ((struct winsize
*) arg
)->ws_ypixel
2396 || get_ttyp ()->winsize
.ws_xpixel
!= ((struct winsize
*) arg
)->ws_xpixel
2399 if (get_ttyp ()->pcon_activated
&& get_ttyp ()->nat_pipe_owner_pid
)
2400 resize_pseudo_console ((struct winsize
*) arg
);
2401 get_ttyp ()->winsize
= *(struct winsize
*) arg
;
2402 get_ttyp ()->kill_pgrp (SIGWINCH
);
2406 *((pid_t
*) arg
) = this->tcgetpgrp ();
2409 return this->tcsetpgrp ((pid_t
) (intptr_t) arg
);
2413 if (!bytes_available (n
))
2418 *(int *) arg
= (int) n
;
2422 return fhandler_base::ioctl (cmd
, arg
);
2428 fhandler_pty_master::ptsname_r (char *buf
, size_t buflen
)
2430 char tmpbuf
[TTY_NAME_MAX
];
2432 __ptsname (tmpbuf
, get_minor ());
2433 if (buflen
<= strlen (tmpbuf
))
2438 strcpy (buf
, tmpbuf
);
2443 fhandler_pty_common::set_close_on_exec (bool val
)
2445 // Cygwin processes will handle this specially on exec.
2446 close_on_exec (val
);
2450 fhandler_pty_slave::setup_locale (void)
2452 extern UINT
__eval_codepage_from_internal_charset ();
2454 if (!get_ttyp ()->term_code_page
)
2456 get_ttyp ()->term_code_page
= __eval_codepage_from_internal_charset ();
2457 acquire_attach_mutex (mutex_timeout
);
2458 SetConsoleCP (get_ttyp ()->term_code_page
);
2459 SetConsoleOutputCP (get_ttyp ()->term_code_page
);
2460 release_attach_mutex ();
2465 fhandler_pty_slave::bg_check (int sig
, bool dontsignal
)
2467 reset_switch_to_nat_pipe ();
2468 return fhandler_termios::bg_check (sig
, dontsignal
);
2472 fhandler_pty_slave::fixup_after_fork (HANDLE parent
)
2474 create_invisible_console ();
2476 // fork_fixup (parent, inuse, "inuse");
2477 // fhandler_pty_common::fixup_after_fork (parent);
2478 report_tty_counts (this, "inherited", "");
2482 fhandler_pty_slave::fixup_after_exec ()
2484 if (!close_on_exec ())
2485 fixup_after_fork (NULL
); /* No parent handle required. */
2487 /* Hook Console API */
2488 #define DO_HOOK(module, name) \
2491 void *api = hook_api (module, #name, (void *) name##_Hooked); \
2492 name##_Orig = (__typeof__ (name) *) api; \
2493 /*if (api) system_printf (#name " hooked.");*/ \
2495 /* CreateProcess() is hooked for GDB etc. */
2496 DO_HOOK (NULL
, CreateProcessA
);
2497 DO_HOOK (NULL
, CreateProcessW
);
2500 /* This thread function handles the master control pipe. It waits for a
2501 client to connect. Then it checks if the client process has permissions
2502 to access the tty handles. If so, it opens the client process and
2503 duplicates the handles into that process. If that fails, it sends a reply
2504 with at least one handle set to NULL and an error code. Last but not
2505 least, the client is disconnected and the thread waits for the next client.
2507 A special case is when the master side of the tty is about to be closed.
2508 The client side is the fhandler_pty_master::close function and it sends
2509 a PID -1 in that case. A check is performed that the request to leave
2510 really comes from the master process itself.
2512 Since there's always only one pipe instance, there's a chance that clients
2513 have to wait to connect to the master control pipe. Therefore the client
2514 calls to CallNamedPipe should have a big enough timeout value. For now this
2515 is 500ms. Hope that's enough. */
2517 /* The function pty_master_thread() should be static because the instance
2518 is deleted if the master is dup()'ed and the original is closed. In
2519 this case, dup()'ed instance still exists, therefore, master thread
2520 is also still alive even though the instance has been deleted. As a
2521 result, accesing member variables in this function causes access
2525 fhandler_pty_master::pty_master_thread (const master_thread_param_t
*p
)
2528 GENERIC_MAPPING map
= { EVENT_QUERY_STATE
, EVENT_MODIFY_STATE
, 0,
2529 EVENT_QUERY_STATE
| EVENT_MODIFY_STATE
};
2532 security_descriptor sd
;
2538 termios_printf ("Entered");
2539 while (!exit
&& (ConnectNamedPipe (p
->master_ctl
, NULL
)
2540 || GetLastError () == ERROR_PIPE_CONNECTED
))
2542 pipe_reply repl
= { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, 0 };
2544 NTSTATUS allow
= STATUS_ACCESS_DENIED
;
2545 ACCESS_MASK access
= EVENT_MODIFY_STATE
;
2546 HANDLE client
= NULL
;
2548 if (!ReadFile (p
->master_ctl
, &req
, sizeof req
, &len
, NULL
))
2550 termios_printf ("ReadFile, %E");
2553 if (!GetNamedPipeClientProcessId (p
->master_ctl
, &pid
))
2555 if (get_object_sd (p
->input_available_event
, sd
))
2557 termios_printf ("get_object_sd, %E");
2560 cygheap
->user
.deimpersonate ();
2562 if (!ImpersonateNamedPipeClient (p
->master_ctl
))
2564 termios_printf ("ImpersonateNamedPipeClient, %E");
2567 status
= NtOpenThreadToken (GetCurrentThread (), TOKEN_QUERY
, TRUE
,
2569 if (!NT_SUCCESS (status
))
2571 termios_printf ("NtOpenThreadToken, %y", status
);
2572 SetLastError (RtlNtStatusToDosError (status
));
2576 status
= NtAccessCheck (sd
, token
, access
, &map
, &ps
, &len
, &access
,
2579 if (!NT_SUCCESS (status
))
2581 termios_printf ("NtAccessCheck, %y", status
);
2582 SetLastError (RtlNtStatusToDosError (status
));
2585 if (!RevertToSelf ())
2587 termios_printf ("RevertToSelf, %E");
2590 if (req
.pid
== (DWORD
) -1) /* Request to finish thread. */
2592 /* Check if the requesting process is the master process itself. */
2593 if (pid
== GetCurrentProcessId ())
2597 if (NT_SUCCESS (allow
))
2599 client
= OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, pid
);
2602 termios_printf ("OpenProcess, %E");
2605 if (!DuplicateHandle (GetCurrentProcess (), p
->from_master_nat
,
2606 client
, &repl
.from_master_nat
,
2607 0, TRUE
, DUPLICATE_SAME_ACCESS
))
2609 termios_printf ("DuplicateHandle (from_master_nat), %E");
2612 if (!DuplicateHandle (GetCurrentProcess (), p
->from_master
,
2613 client
, &repl
.from_master
,
2614 0, TRUE
, DUPLICATE_SAME_ACCESS
))
2616 termios_printf ("DuplicateHandle (from_master), %E");
2619 if (!DuplicateHandle (GetCurrentProcess (), p
->to_master_nat
,
2620 client
, &repl
.to_master_nat
,
2621 0, TRUE
, DUPLICATE_SAME_ACCESS
))
2623 termios_printf ("DuplicateHandle (to_master_nat), %E");
2626 if (!DuplicateHandle (GetCurrentProcess (), p
->to_master
,
2627 client
, &repl
.to_master
,
2628 0, TRUE
, DUPLICATE_SAME_ACCESS
))
2630 termios_printf ("DuplicateHandle (to_master), %E");
2633 if (!DuplicateHandle (GetCurrentProcess (), p
->to_slave_nat
,
2634 client
, &repl
.to_slave_nat
,
2635 0, TRUE
, DUPLICATE_SAME_ACCESS
))
2637 termios_printf ("DuplicateHandle (to_slave_nat), %E");
2640 if (!DuplicateHandle (GetCurrentProcess (), p
->to_slave
,
2641 client
, &repl
.to_slave
,
2642 0, TRUE
, DUPLICATE_SAME_ACCESS
))
2644 termios_printf ("DuplicateHandle (to_slave), %E");
2649 repl
.error
= GetLastError ();
2651 CloseHandle (client
);
2653 cygheap
->user
.reimpersonate ();
2655 termios_printf ("Reply: from %p, to %p, error %u",
2656 repl
.from_master_nat
, repl
.to_master_nat
, repl
.error
);
2657 if (!WriteFile (p
->master_ctl
, &repl
, sizeof repl
, &len
, NULL
))
2658 termios_printf ("WriteFile, %E");
2659 if (!DisconnectNamedPipe (p
->master_ctl
))
2660 termios_printf ("DisconnectNamedPipe, %E");
2662 termios_printf ("Leaving");
2667 pty_master_thread (VOID
*arg
)
2669 fhandler_pty_master::master_thread_param_t p
;
2670 ((fhandler_pty_master
*) arg
)->get_master_thread_param (&p
);
2671 return fhandler_pty_master::pty_master_thread (&p
);
2674 /* The function pty_master_fwd_thread() should be static because the
2675 instance is deleted if the master is dup()'ed and the original is
2676 closed. In this case, dup()'ed instance still exists, therefore,
2677 master forwarding thread is also still alive even though the instance
2678 has been deleted. As a result, accesing member variables in this
2679 function causes access violation. */
2682 fhandler_pty_master::pty_master_fwd_thread (const master_fwd_thread_param_t
*p
)
2686 char *outbuf
= tp
.c_get ();
2687 char *mbbuf
= tp
.c_get ();
2688 static mbstate_t mbp
;
2690 termios_printf ("Started.");
2693 p
->ttyp
->fwd_last_time
= GetTickCount64 ();
2695 p
->ttyp
->fwd_not_empty
=
2696 ::bytes_available (n
, p
->from_slave_nat
) && n
;
2697 if (!ReadFile (p
->from_slave_nat
, outbuf
, NT_MAX_PATH
, &rlen
, NULL
))
2699 termios_printf ("ReadFile for forwarding failed, %E");
2702 if (p
->ttyp
->stop_fwd_thread
)
2704 ssize_t wlen
= rlen
;
2706 if (p
->ttyp
->pcon_activated
)
2708 /* Avoid setting window title to "cygwin-console-helper.exe" */
2711 for (DWORD i
=0; i
<rlen
; i
++)
2712 if (outbuf
[i
] == '\033')
2718 else if ((state
== 1 && outbuf
[i
] == ']') ||
2719 (state
== 2 && outbuf
[i
] == '0') ||
2720 (state
== 3 && outbuf
[i
] == ';'))
2725 else if (state
== 4 && outbuf
[i
] == '\a')
2727 const char *helper_str
= "\\bin\\cygwin-console-helper.exe";
2728 if (memmem (&outbuf
[start_at
], i
+ 1 - start_at
,
2729 helper_str
, strlen (helper_str
)))
2731 memmove (&outbuf
[start_at
], &outbuf
[i
+1], rlen
-i
-1);
2732 rlen
= wlen
= start_at
+ rlen
- i
- 1;
2737 else if (outbuf
[i
] == '\a')
2743 /* Remove CSI > Pm m */
2746 for (DWORD i
= 0; i
< rlen
; i
++)
2747 if (outbuf
[i
] == '\033')
2753 else if ((state
== 1 && outbuf
[i
] == '[')
2754 || (state
== 2 && outbuf
[i
] == '>'))
2759 else if (state
== 3 && (isdigit (outbuf
[i
]) || outbuf
[i
] == ';'))
2761 else if (state
== 3 && outbuf
[i
] == 'm')
2763 memmove (&outbuf
[start_at
], &outbuf
[i
+1], rlen
-i
-1);
2764 rlen
= wlen
= start_at
+ rlen
- i
- 1;
2772 /* Remove OSC Ps ; ? BEL/ST */
2773 for (DWORD i
= 0; i
< rlen
; i
++)
2774 if (state
== 0 && outbuf
[i
] == '\033')
2780 else if ((state
== 1 && outbuf
[i
] == ']')
2781 || (state
== 2 && outbuf
[i
] == ';')
2782 || (state
== 3 && outbuf
[i
] == '?')
2783 || (state
== 4 && outbuf
[i
] == '\033'))
2788 else if (state
== 2 && isdigit (outbuf
[i
]))
2790 else if ((state
== 4 && outbuf
[i
] == '\a')
2791 || (state
== 5 && outbuf
[i
] == '\\'))
2793 memmove (&outbuf
[start_at
], &outbuf
[i
+1], rlen
-i
-1);
2794 rlen
= wlen
= start_at
+ rlen
- i
- 1;
2802 if (p
->ttyp
->term_code_page
!= CP_UTF8
)
2804 size_t nlen
= NT_MAX_PATH
;
2805 convert_mb_str (p
->ttyp
->term_code_page
, mbbuf
, &nlen
,
2806 CP_UTF8
, ptr
, wlen
, &mbp
);
2812 /* OPOST processing was already done in pseudo console,
2813 so just write it to to_master. */
2817 if (!WriteFile (p
->to_master
, ptr
, wlen
, &written
, NULL
))
2819 termios_printf ("WriteFile for forwarding failed, %E");
2823 wlen
= (rlen
-= written
);
2829 pinfo pinfo_target
= pinfo (p
->ttyp
->invisible_console_pid
);
2830 DWORD target_pid
= 0;
2832 target_pid
= pinfo_target
->dwProcessId
;
2835 /* Slave attaches to a different console than master.
2836 Therefore reattach here. */
2838 attach_console_temporarily (target_pid
);
2839 cp_from
= GetConsoleOutputCP ();
2840 resume_from_temporarily_attach (resume_pid
);
2843 cp_from
= GetConsoleOutputCP ();
2845 if (p
->ttyp
->term_code_page
!= cp_from
)
2847 size_t nlen
= NT_MAX_PATH
;
2848 convert_mb_str (p
->ttyp
->term_code_page
, mbbuf
, &nlen
,
2849 cp_from
, ptr
, wlen
, &mbp
);
2855 WaitForSingleObject (p
->output_mutex
, mutex_timeout
);
2858 if (!process_opost_output (p
->to_master
, ptr
, wlen
,
2859 true /* disable output_stopped */,
2862 termios_printf ("WriteFile for forwarding failed, %E");
2866 wlen
= (rlen
-= wlen
);
2868 ReleaseMutex (p
->output_mutex
);
2874 pty_master_fwd_thread (VOID
*arg
)
2876 fhandler_pty_master::master_fwd_thread_param_t p
;
2877 ((fhandler_pty_master
*) arg
)->get_master_fwd_thread_param (&p
);
2878 return fhandler_pty_master::pty_master_fwd_thread (&p
);
2882 is_running_as_service (void)
2884 return check_token_membership (well_known_service_sid
)
2885 || cygheap
->user
.saved_sid () == well_known_system_sid
;
2889 fhandler_pty_master::setup ()
2892 security_descriptor sd
;
2893 SECURITY_ATTRIBUTES sa
= { sizeof (SECURITY_ATTRIBUTES
), NULL
, TRUE
};
2895 /* Find an unallocated pty to use. */
2896 /* Create a pipe for cygwin app (master to slave) simultaneously. */
2897 int unit
= cygwin_shared
->tty
.allocate (from_master
, get_output_handle ());
2901 ProtectHandle1 (get_output_handle (), to_pty
);
2903 tty
& t
= *cygwin_shared
->tty
[unit
];
2904 _tc
= (tty_min
*) &t
;
2906 tcinit (true); /* Set termios information. Force initialization. */
2908 const char *errstr
= NULL
;
2909 DWORD pipe_mode
= PIPE_NOWAIT
;
2911 if (!SetNamedPipeHandleState (get_output_handle (), &pipe_mode
, NULL
, NULL
))
2912 termios_printf ("can't set output_handle(%p) to non-blocking mode",
2913 get_output_handle ());
2915 /* Pipe for non-cygwin apps (slave to master) */
2916 char pipename
[sizeof ("ptyNNNN-from-master-nat")];
2917 __small_sprintf (pipename
, "pty%d-to-master-nat", unit
);
2918 res
= fhandler_pipe::create (&sec_none
, &from_slave_nat
, &to_master_nat
,
2919 fhandler_pty_common::pipesize
, pipename
, 0);
2922 errstr
= "output pipe for non-cygwin apps";
2926 /* Pipe for cygwin apps (slave to master) */
2927 __small_sprintf (pipename
, "pty%d-to-master", unit
);
2928 res
= fhandler_pipe::create (&sec_none
, &get_handle (), &to_master
,
2929 fhandler_pty_common::pipesize
, pipename
, 0);
2932 errstr
= "output pipe";
2936 /* Pipe for non-cygwin apps (master to slave) */
2937 __small_sprintf (pipename
, "pty%d-from-master-nat", unit
);
2938 /* FILE_FLAG_OVERLAPPED is specified here in order to prevent
2939 PeekNamedPipe() from blocking in transfer_input().
2940 Accordig to the official document, in order to access the handle
2941 opened with FILE_FLAG_OVERLAPPED, it is mandatory to pass the
2942 OVERLAPP structure, but in fact, it seems that the access will
2943 fallback to the blocking access if it is not specified. */
2944 res
= fhandler_pipe::create (&sec_none
, &from_master_nat
, &to_slave_nat
,
2945 fhandler_pty_common::pipesize
, pipename
,
2946 FILE_FLAG_OVERLAPPED
);
2949 errstr
= "input pipe";
2953 ProtectHandle1 (get_handle (), from_pty
);
2955 __small_sprintf (pipename
, "pty%d-echoloop", unit
);
2956 res
= fhandler_pipe::create (&sec_none
, &echo_r
, &echo_w
,
2957 fhandler_pty_common::pipesize
, pipename
, 0);
2960 errstr
= "echo pipe";
2964 /* Create security attribute. Default permissions are 0620. */
2965 sd
.malloc (sizeof (SECURITY_DESCRIPTOR
));
2966 RtlCreateSecurityDescriptor (sd
, SECURITY_DESCRIPTOR_REVISION
);
2967 if (!create_object_sd_from_attribute (myself
->uid
, myself
->gid
,
2968 S_IFCHR
| S_IRUSR
| S_IWUSR
| S_IWGRP
,
2970 sa
.lpSecurityDescriptor
= (PSECURITY_DESCRIPTOR
) sd
;
2972 /* Carefully check that the input_available_event didn't already exist.
2973 This is a measure to make sure that the event security descriptor
2974 isn't occupied by a malicious process. We must make sure that the
2975 event's security descriptor is what we expect it to be. */
2976 if (!(input_available_event
= t
.get_event (errstr
= INPUT_AVAILABLE_EVENT
,
2978 || GetLastError () == ERROR_ALREADY_EXISTS
)
2982 errstr
= shared_name (buf
, OUTPUT_MUTEX
, unit
);
2983 if (!(output_mutex
= CreateMutex (&sa
, FALSE
, buf
)))
2986 errstr
= shared_name (buf
, INPUT_MUTEX
, unit
);
2987 if (!(input_mutex
= CreateMutex (&sa
, FALSE
, buf
)))
2990 errstr
= shared_name (buf
, PIPE_SW_MUTEX
, unit
);
2991 if (!(pipe_sw_mutex
= CreateMutex (&sa
, FALSE
, buf
)))
2995 attach_mutex
= CreateMutex (&sec_none_nih
, FALSE
, NULL
);
2997 /* Create master control pipe which allows the master to duplicate
2998 the pty pipe handles to processes which deserve it. */
2999 __small_sprintf (buf
, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
3000 &cygheap
->installation_key
, unit
);
3001 master_ctl
= CreateNamedPipe (buf
, PIPE_ACCESS_DUPLEX
3002 | FILE_FLAG_FIRST_PIPE_INSTANCE
,
3003 PIPE_WAIT
| PIPE_TYPE_MESSAGE
3004 | PIPE_READMODE_MESSAGE
3005 | PIPE_REJECT_REMOTE_CLIENTS
,
3006 1, 4096, 4096, 0, &sec_all_nih
);
3007 if (master_ctl
== INVALID_HANDLE_VALUE
)
3009 errstr
= "pty master control pipe";
3013 thread_param_copied_event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
3014 master_thread
= new cygthread (::pty_master_thread
, this, "ptym");
3017 errstr
= "pty master control thread";
3020 WaitForSingleObject (thread_param_copied_event
, INFINITE
);
3022 master_fwd_thread
= new cygthread (::pty_master_fwd_thread
, this, "ptymf");
3023 if (!master_fwd_thread
)
3025 errstr
= "pty master forwarding thread";
3028 WaitForSingleObject (thread_param_copied_event
, INFINITE
);
3029 CloseHandle (thread_param_copied_event
);
3031 t
.set_from_master_nat (from_master_nat
);
3032 t
.set_from_master (from_master
);
3033 t
.set_to_master_nat (to_master_nat
);
3034 t
.set_to_master (to_master
);
3035 t
.set_to_slave_nat (to_slave_nat
);
3036 t
.set_to_slave (get_output_handle ());
3037 t
.winsize
.ws_col
= 80;
3038 t
.winsize
.ws_row
= 25;
3039 t
.master_pid
= myself
->pid
;
3041 dev ().parse (DEV_PTYM_MAJOR
, unit
);
3043 t
.master_is_running_as_service
= is_running_as_service ();
3045 termios_printf ("this %p, pty%d opened - from_pty <%p,%p>, to_pty %p",
3046 this, unit
, from_slave_nat
, get_handle (),
3047 get_output_handle ());
3052 close_maybe (from_slave_nat
);
3053 close_maybe (to_slave_nat
);
3054 close_maybe (get_handle ());
3055 close_maybe (get_output_handle ());
3056 close_maybe (input_available_event
);
3057 close_maybe (output_mutex
);
3058 close_maybe (input_mutex
);
3059 close_maybe (from_master_nat
);
3060 close_maybe (to_master_nat
);
3061 close_maybe (to_master
);
3062 close_maybe (echo_r
);
3063 close_maybe (echo_w
);
3064 close_maybe (master_ctl
);
3065 /* The from_master must be closed last so that the same pty is not
3066 allocated before cleaning up the other corresponding instances. */
3067 close_maybe (from_master
);
3068 termios_printf ("pty%d open failed - failed to create %s", unit
, errstr
);
3073 fhandler_pty_master::fixup_after_fork (HANDLE parent
)
3075 DWORD wpid
= GetCurrentProcessId ();
3076 fhandler_pty_master
*arch
= (fhandler_pty_master
*) archetype
;
3077 if (arch
->dwProcessId
!= wpid
)
3079 tty
& t
= *get_ttyp ();
3080 if (myself
->pid
== t
.master_pid
)
3082 t
.set_from_master_nat (arch
->from_master_nat
);
3083 t
.set_from_master (arch
->from_master
);
3084 t
.set_to_master_nat (arch
->to_master_nat
);
3085 t
.set_to_master (arch
->to_master
);
3087 arch
->dwProcessId
= wpid
;
3089 from_master_nat
= arch
->from_master_nat
;
3090 from_master
= arch
->from_master
;
3091 to_master_nat
= arch
->to_master_nat
;
3092 to_master
= arch
->to_master
;
3093 #if 0 /* Not sure if this is necessary. */
3094 from_slave_nat
= arch
->from_slave_nat
;
3095 to_slave_nat
= arch
->to_slave_nat
;
3097 report_tty_counts (this, "inherited master", "");
3101 fhandler_pty_master::fixup_after_exec ()
3103 if (!close_on_exec ())
3104 fixup_after_fork (spawn_info
->parent
);
3106 from_master_nat
= from_master
= to_master_nat
= to_master
=
3107 from_slave_nat
= to_slave_nat
= NULL
;
3111 fhandler_pty_common::process_opost_output (HANDLE h
, const void *ptr
,
3112 ssize_t
& len
, bool is_echo
,
3113 tty
*ttyp
, bool is_nonblocking
)
3115 ssize_t towrite
= len
;
3117 if (ttyp
->ti
.c_lflag
& FLUSHO
)
3118 return res
; /* Discard write data */
3123 if (ttyp
->output_stopped
&& is_nonblocking
)
3134 while (ttyp
->output_stopped
)
3138 if (!(ttyp
->ti
.c_oflag
& OPOST
)) // raw output mode
3140 DWORD n
= MIN (OUT_BUFFER_SIZE
, towrite
);
3141 res
= WriteFile (h
, ptr
, n
, &n
, NULL
);
3144 ptr
= (char *) ptr
+ n
;
3147 else // post-process output
3149 char outbuf
[OUT_BUFFER_SIZE
+ 1];
3150 char *buf
= (char *)ptr
;
3153 while (n
< OUT_BUFFER_SIZE
&& rc
< towrite
)
3158 if ((ttyp
->ti
.c_oflag
& ONOCR
)
3159 && ttyp
->column
== 0)
3164 if (ttyp
->ti
.c_oflag
& OCRNL
)
3171 outbuf
[n
++] = buf
[rc
++];
3176 if (ttyp
->ti
.c_oflag
& ONLCR
)
3181 if (ttyp
->ti
.c_oflag
& ONLRET
)
3183 outbuf
[n
++] = buf
[rc
++];
3186 outbuf
[n
++] = buf
[rc
++];
3191 res
= WriteFile (h
, outbuf
, n
, &n
, NULL
);
3194 ptr
= (char *) ptr
+ rc
;
3202 /* Pseudo console supprot is realized using a tricky technic.
3203 PTY need the pseudo console handles, however, they cannot
3204 be retrieved by normal procedure. Therefore, run a helper
3205 process in a pseudo console and get them from the helper.
3206 Slave process will attach to the pseudo console in the
3207 helper process using AttachConsole(). */
3209 fhandler_pty_slave::setup_pseudoconsole ()
3211 /* If the legacy console mode is enabled, pseudo console seems
3212 not to work as expected. To determine console mode, registry
3213 key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
3214 reg_key
reg (HKEY_CURRENT_USER
, KEY_READ
, L
"Console", NULL
);
3217 if (reg
.get_dword (L
"ForceV2", 1) == 0)
3219 termios_printf ("Pseudo console is disabled "
3220 "because the legacy console mode is enabled.");
3224 /* Set switch_to_nat_pipe regardless whether stdin is the pty or not
3225 so that the non-cygwin app can work when it opens CONIN$. */
3226 bool switch_to_nat_pipe_orig
= get_ttyp ()->switch_to_nat_pipe
;
3227 get_ttyp ()->switch_to_nat_pipe
= true;
3229 HANDLE hpConIn
, hpConOut
;
3230 if (get_ttyp ()->pcon_activated
)
3231 { /* The pseudo console is already activated. */
3232 if (GetStdHandle (STD_INPUT_HANDLE
) == get_handle ())
3233 { /* Send CSI6n just for requesting transfer input. */
3235 WaitForSingleObject (input_mutex
, mutex_timeout
);
3236 get_ttyp ()->req_xfer_input
= true; /* indicates that this "ESC[6n"
3237 is just for transfer input */
3238 get_ttyp ()->pcon_start
= true;
3239 get_ttyp ()->pcon_start_pid
= myself
->pid
;
3240 WriteFile (get_output_handle (), "\033[6n", 4, &n
, NULL
);
3241 ReleaseMutex (input_mutex
);
3242 while (get_ttyp ()->pcon_start_pid
)
3243 /* wait for completion of transfer_input() in master::write(). */
3246 /* Attach to the pseudo console which already exits. */
3247 HANDLE pcon_owner
= OpenProcess (PROCESS_DUP_HANDLE
, FALSE
,
3248 get_ttyp ()->nat_pipe_owner_pid
);
3249 if (pcon_owner
== NULL
)
3251 DuplicateHandle (pcon_owner
, get_ttyp ()->h_pcon_in
,
3252 GetCurrentProcess (), &hpConIn
,
3253 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3254 DuplicateHandle (pcon_owner
, get_ttyp ()->h_pcon_out
,
3255 GetCurrentProcess (), &hpConOut
,
3256 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3257 CloseHandle (pcon_owner
);
3258 acquire_attach_mutex (mutex_timeout
);
3260 AttachConsole (get_ttyp ()->nat_pipe_owner_pid
);
3261 init_console_handler (false);
3262 release_attach_mutex ();
3267 PROCESS_INFORMATION pi
;
3268 HANDLE hello
, goodbye
;
3273 { /* Create new pseudo console */
3275 (SHORT
) get_ttyp ()->winsize
.ws_col
,
3276 (SHORT
) get_ttyp ()->winsize
.ws_row
3278 const DWORD inherit_cursor
= 1;
3280 SetLastError (ERROR_SUCCESS
);
3281 HRESULT res
= CreatePseudoConsole (size
, get_handle_nat (),
3282 get_output_handle_nat (),
3283 inherit_cursor
, &hpcon
);
3284 if (res
!= S_OK
|| GetLastError () == ERROR_PROC_NOT_FOUND
)
3287 system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
3288 GetLastError (), res
);
3292 SIZE_T bytesRequired
;
3293 InitializeProcThreadAttributeList (NULL
, 2, 0, &bytesRequired
);
3294 ZeroMemory (&si
, sizeof (si
));
3295 si
.StartupInfo
.cb
= sizeof (STARTUPINFOEXW
);
3296 si
.lpAttributeList
= (PPROC_THREAD_ATTRIBUTE_LIST
)
3297 HeapAlloc (GetProcessHeap (), 0, bytesRequired
);
3298 if (si
.lpAttributeList
== NULL
)
3299 goto cleanup_pseudo_console
;
3300 if (!InitializeProcThreadAttributeList (si
.lpAttributeList
,
3301 2, 0, &bytesRequired
))
3303 if (!UpdateProcThreadAttribute (si
.lpAttributeList
,
3305 PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
,
3306 hpcon
, sizeof (hpcon
), NULL
, NULL
))
3310 hello
= CreateEvent (&sec_none
, true, false, NULL
);
3311 goodbye
= CreateEvent (&sec_none
, true, false, NULL
);
3312 CreatePipe (&hr
, &hw
, &sec_none
, 0);
3314 HANDLE handles_to_inherit
[] = {hello
, goodbye
, hw
};
3315 if (!UpdateProcThreadAttribute (si
.lpAttributeList
,
3317 PROC_THREAD_ATTRIBUTE_HANDLE_LIST
,
3319 sizeof (handles_to_inherit
),
3321 goto cleanup_event_and_pipes
;
3323 /* Execute helper process */
3324 WCHAR cmd
[MAX_PATH
];
3325 path_conv
helper ("/bin/cygwin-console-helper.exe");
3326 size_t len
= helper
.get_wide_win32_path_len ();
3327 helper
.get_wide_win32_path (cmd
);
3328 __small_swprintf (cmd
+ len
, L
" %p %p %p", hello
, goodbye
, hw
);
3329 si
.StartupInfo
.dwFlags
= STARTF_USESTDHANDLES
;
3330 si
.StartupInfo
.hStdInput
= NULL
;
3331 si
.StartupInfo
.hStdOutput
= NULL
;
3332 si
.StartupInfo
.hStdError
= NULL
;
3334 get_ttyp ()->pcon_activated
= true;
3335 get_ttyp ()->pcon_start
= true;
3336 get_ttyp ()->pcon_start_pid
= myself
->pid
;
3337 if (!CreateProcessW (NULL
, cmd
, &sec_none
, &sec_none
,
3338 TRUE
, EXTENDED_STARTUPINFO_PRESENT
,
3339 NULL
, NULL
, &si
.StartupInfo
, &pi
))
3340 goto cleanup_event_and_pipes
;
3344 DWORD wait_result
= WaitForSingleObject (hello
, 500);
3345 if (wait_result
== WAIT_OBJECT_0
)
3347 if (wait_result
!= WAIT_TIMEOUT
)
3348 goto cleanup_helper_with_hello
;
3350 if (!GetExitCodeProcess (pi
.hProcess
, &exit_code
))
3351 goto cleanup_helper_with_hello
;
3352 if (exit_code
== STILL_ACTIVE
)
3354 if (exit_code
!= 0 ||
3355 WaitForSingleObject (hello
, 500) != WAIT_OBJECT_0
)
3356 goto cleanup_helper_with_hello
;
3359 CloseHandle (hello
);
3360 CloseHandle (pi
.hThread
);
3362 /* Duplicate pseudo console handles */
3365 if (!ReadFile (hr
, buf
, sizeof (buf
), &rlen
, NULL
))
3366 goto cleanup_helper_process
;
3368 sscanf (buf
, "StdHandles=%p,%p", &hpConIn
, &hpConOut
);
3369 if (!DuplicateHandle (pi
.hProcess
, hpConIn
,
3370 GetCurrentProcess (), &hpConIn
, 0,
3371 TRUE
, DUPLICATE_SAME_ACCESS
))
3372 goto cleanup_helper_process
;
3373 if (!DuplicateHandle (pi
.hProcess
, hpConOut
,
3374 GetCurrentProcess (), &hpConOut
, 0,
3375 TRUE
, DUPLICATE_SAME_ACCESS
))
3376 goto cleanup_pcon_in
;
3380 DeleteProcThreadAttributeList (si
.lpAttributeList
);
3381 HeapFree (GetProcessHeap (), 0, si
.lpAttributeList
);
3383 /* Attach to pseudo console */
3384 acquire_attach_mutex (mutex_timeout
);
3386 AttachConsole (pi
.dwProcessId
);
3387 init_console_handler (false);
3388 release_attach_mutex ();
3390 /* Terminate helper process */
3392 WaitForSingleObject (pi
.hProcess
, INFINITE
);
3393 CloseHandle (goodbye
);
3394 CloseHandle (pi
.hProcess
);
3402 HANDLE orig_input_handle_nat
= get_handle_nat ();
3403 HANDLE orig_output_handle_nat
= get_output_handle_nat ();
3404 cygheap_fdenum
cfd (false);
3405 while (cfd
.next () >= 0)
3406 if (cfd
->get_device () == get_device ())
3408 fhandler_base
*fh
= cfd
;
3409 fhandler_pty_slave
*ptys
= (fhandler_pty_slave
*) fh
;
3410 if (ptys
->get_handle_nat () == orig_input_handle_nat
)
3411 ptys
->set_handle_nat (hpConIn
);
3412 if (ptys
->get_output_handle_nat () == orig_output_handle_nat
)
3413 ptys
->set_output_handle_nat (hpConOut
);
3415 CloseHandle (orig_input_handle_nat
);
3416 CloseHandle (orig_output_handle_nat
);
3420 if (!process_alive (get_ttyp ()->nat_pipe_owner_pid
))
3421 get_ttyp ()->nat_pipe_owner_pid
= myself
->exec_dwProcessId
;
3423 if (hpcon
&& nat_pipe_owner_self (get_ttyp ()->nat_pipe_owner_pid
))
3425 HPCON_INTERNAL
*hp
= (HPCON_INTERNAL
*) hpcon
;
3426 get_ttyp ()->h_pcon_write_pipe
= hp
->hWritePipe
;
3427 get_ttyp ()->h_pcon_condrv_reference
= hp
->hConDrvReference
;
3428 get_ttyp ()->h_pcon_conhost_process
= hp
->hConHostProcess
;
3429 DuplicateHandle (GetCurrentProcess (), hpConIn
,
3430 GetCurrentProcess (), &get_ttyp ()->h_pcon_in
,
3431 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3432 DuplicateHandle (GetCurrentProcess (), hpConOut
,
3433 GetCurrentProcess (), &get_ttyp ()->h_pcon_out
,
3434 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3435 /* Discard the pseudo console handler container here.
3436 Reconstruct it temporary when it is needed. */
3437 HeapFree (GetProcessHeap (), 0, hp
);
3440 acquire_attach_mutex (mutex_timeout
);
3441 if (get_ttyp ()->previous_code_page
)
3442 SetConsoleCP (get_ttyp ()->previous_code_page
);
3443 if (get_ttyp ()->previous_output_code_page
)
3444 SetConsoleOutputCP (get_ttyp ()->previous_output_code_page
);
3446 if (get_ttyp ()->getpgid () == myself
->pgid
)
3448 termios
&t
= get_ttyp ()->ti
;
3450 /* Set input mode */
3451 GetConsoleMode (hpConIn
, &mode
);
3452 mode
&= ~(ENABLE_ECHO_INPUT
| ENABLE_LINE_INPUT
| ENABLE_PROCESSED_INPUT
);
3453 if (t
.c_lflag
& ECHO
)
3454 mode
|= ENABLE_ECHO_INPUT
;
3455 if (t
.c_lflag
& ICANON
)
3456 mode
|= ENABLE_LINE_INPUT
;
3457 if (mode
& ENABLE_ECHO_INPUT
&& !(mode
& ENABLE_LINE_INPUT
))
3458 /* This is illegal, so turn off the echo here, and fake it
3459 when we read the characters */
3460 mode
&= ~ENABLE_ECHO_INPUT
;
3461 if (t
.c_lflag
& ISIG
)
3462 mode
|= ENABLE_PROCESSED_INPUT
;
3463 SetConsoleMode (hpConIn
, mode
);
3464 /* Set output mode */
3465 GetConsoleMode (hpConOut
, &mode
);
3466 mode
&= ~DISABLE_NEWLINE_AUTO_RETURN
;
3467 if (!(t
.c_oflag
& OPOST
) || !(t
.c_oflag
& ONLCR
))
3468 mode
|= DISABLE_NEWLINE_AUTO_RETURN
;
3469 SetConsoleMode (hpConOut
, mode
);
3471 release_attach_mutex ();
3475 cleanup_helper_with_hello
:
3476 CloseHandle (hello
);
3477 CloseHandle (pi
.hThread
);
3478 goto cleanup_helper_process
;
3480 CloseHandle (hpConIn
);
3481 cleanup_helper_process
:
3483 WaitForSingleObject (pi
.hProcess
, INFINITE
);
3484 CloseHandle (pi
.hProcess
);
3485 goto skip_close_hello
;
3486 cleanup_event_and_pipes
:
3487 CloseHandle (hello
);
3489 get_ttyp ()->pcon_start
= false;
3490 get_ttyp ()->pcon_start_pid
= 0;
3491 get_ttyp ()->pcon_activated
= false;
3492 CloseHandle (goodbye
);
3496 HeapFree (GetProcessHeap (), 0, si
.lpAttributeList
);
3497 cleanup_pseudo_console
:
3500 HPCON_INTERNAL
*hp
= (HPCON_INTERNAL
*) hpcon
;
3501 HANDLE tmp
= hp
->hConHostProcess
;
3502 ClosePseudoConsole (hpcon
);
3506 get_ttyp ()->switch_to_nat_pipe
= switch_to_nat_pipe_orig
;
3510 /* Find a process to which the ownership of nat pipe should be handed over */
3512 fhandler_pty_slave::get_winpid_to_hand_over (tty
*ttyp
,
3513 DWORD force_switch_to
)
3515 DWORD switch_to
= 0;
3516 if (force_switch_to
)
3518 switch_to
= force_switch_to
;
3519 ttyp
->setpgid (force_switch_to
+ MAX_PID
);
3521 else if (nat_pipe_owner_self (ttyp
->nat_pipe_owner_pid
))
3523 /* Search another native process which attaches to the same console */
3524 DWORD current_pid
= myself
->exec_dwProcessId
?: myself
->dwProcessId
;
3525 switch_to
= get_console_process_id (current_pid
,
3526 false, true, true, true);
3528 switch_to
= get_console_process_id (current_pid
,
3529 false, true, false, true);
3535 fhandler_pty_slave::hand_over_only (tty
*ttyp
, DWORD force_switch_to
)
3537 if (nat_pipe_owner_self (ttyp
->nat_pipe_owner_pid
))
3539 DWORD switch_to
= get_winpid_to_hand_over (ttyp
, force_switch_to
);
3541 /* The process switch_to takes over the ownership of the nat pipe. */
3542 ttyp
->nat_pipe_owner_pid
= switch_to
;
3545 /* Abandon the ownership of the nat pipe */
3546 ttyp
->nat_pipe_owner_pid
= 0;
3547 ttyp
->switch_to_nat_pipe
= false;
3552 /* The function close_pseudoconsole() should be static so that it can
3553 be called even after the fhandler_pty_slave instance is deleted. */
3555 fhandler_pty_slave::close_pseudoconsole (tty
*ttyp
, DWORD force_switch_to
)
3557 DWORD switch_to
= get_winpid_to_hand_over (ttyp
, force_switch_to
);
3558 acquire_attach_mutex (mutex_timeout
);
3559 ttyp
->previous_code_page
= GetConsoleCP ();
3560 ttyp
->previous_output_code_page
= GetConsoleOutputCP ();
3561 release_attach_mutex ();
3562 if (nat_pipe_owner_self (ttyp
->nat_pipe_owner_pid
))
3563 { /* I am owner of the nat pipe. */
3566 /* Change pseudo console owner to another process (switch_to). */
3568 OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, switch_to
);
3569 HANDLE new_write_pipe
= NULL
;
3570 HANDLE new_condrv_reference
= NULL
;
3571 HANDLE new_conhost_process
= NULL
;
3572 HANDLE new_pcon_in
= NULL
, new_pcon_out
= NULL
;
3573 DuplicateHandle (GetCurrentProcess (),
3574 ttyp
->h_pcon_write_pipe
,
3575 new_owner
, &new_write_pipe
,
3576 0, FALSE
, DUPLICATE_SAME_ACCESS
);
3577 DuplicateHandle (GetCurrentProcess (),
3578 ttyp
->h_pcon_condrv_reference
,
3579 new_owner
, &new_condrv_reference
,
3580 0, FALSE
, DUPLICATE_SAME_ACCESS
);
3581 DuplicateHandle (GetCurrentProcess (),
3582 ttyp
->h_pcon_conhost_process
,
3583 new_owner
, &new_conhost_process
,
3584 0, FALSE
, DUPLICATE_SAME_ACCESS
);
3585 DuplicateHandle (GetCurrentProcess (), ttyp
->h_pcon_in
,
3586 new_owner
, &new_pcon_in
,
3587 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3588 DuplicateHandle (GetCurrentProcess (), ttyp
->h_pcon_out
,
3589 new_owner
, &new_pcon_out
,
3590 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3591 CloseHandle (new_owner
);
3592 CloseHandle (ttyp
->h_pcon_write_pipe
);
3593 CloseHandle (ttyp
->h_pcon_condrv_reference
);
3594 CloseHandle (ttyp
->h_pcon_conhost_process
);
3595 CloseHandle (ttyp
->h_pcon_in
);
3596 CloseHandle (ttyp
->h_pcon_out
);
3597 ttyp
->nat_pipe_owner_pid
= switch_to
;
3598 ttyp
->h_pcon_write_pipe
= new_write_pipe
;
3599 ttyp
->h_pcon_condrv_reference
= new_condrv_reference
;
3600 ttyp
->h_pcon_conhost_process
= new_conhost_process
;
3601 ttyp
->h_pcon_in
= new_pcon_in
;
3602 ttyp
->h_pcon_out
= new_pcon_out
;
3603 acquire_attach_mutex (mutex_timeout
);
3605 pinfo
p (myself
->ppid
);
3606 if (!p
|| !AttachConsole (p
->dwProcessId
))
3607 AttachConsole (ATTACH_PARENT_PROCESS
);
3608 init_console_handler (false);
3609 release_attach_mutex ();
3612 { /* Close pseudo console and abandon the ownership of the nat pipe. */
3613 acquire_attach_mutex (mutex_timeout
);
3615 pinfo
p (myself
->ppid
);
3616 if (!p
|| !AttachConsole (p
->dwProcessId
))
3617 AttachConsole (ATTACH_PARENT_PROCESS
);
3618 init_console_handler (false);
3619 release_attach_mutex ();
3620 /* Reconstruct pseudo console handler container here for close */
3621 HPCON_INTERNAL
*hp
=
3622 (HPCON_INTERNAL
*) HeapAlloc (GetProcessHeap (), 0,
3623 sizeof (HPCON_INTERNAL
));
3624 hp
->hWritePipe
= ttyp
->h_pcon_write_pipe
;
3625 hp
->hConDrvReference
= ttyp
->h_pcon_condrv_reference
;
3626 hp
->hConHostProcess
= ttyp
->h_pcon_conhost_process
;
3627 /* HeapFree() will be called in ClosePseudoConsole() */
3628 ClosePseudoConsole ((HPCON
) hp
);
3629 CloseHandle (ttyp
->h_pcon_conhost_process
);
3630 ttyp
->pcon_activated
= false;
3631 ttyp
->switch_to_nat_pipe
= false;
3632 ttyp
->nat_pipe_owner_pid
= 0;
3633 ttyp
->pcon_start
= false;
3634 ttyp
->pcon_start_pid
= 0;
3638 { /* Just detach from the pseudo console if I am not owner. */
3639 acquire_attach_mutex (mutex_timeout
);
3641 pinfo
p (myself
->ppid
);
3642 if (!p
|| !AttachConsole (p
->dwProcessId
))
3643 AttachConsole (ATTACH_PARENT_PROCESS
);
3644 init_console_handler (false);
3645 release_attach_mutex ();
3650 has_ansi_escape_sequences (const WCHAR
*env
)
3652 /* Retrieve TERM name */
3653 const char *term
= NULL
;
3657 for (const WCHAR
*p
= env
; *p
!= L
'\0'; p
+= wcslen (p
) + 1)
3658 if (swscanf (p
, L
"TERM=%236s", term_str
) == 1)
3665 term
= getenv ("TERM");
3670 /* If cursor_home is not "\033[H", terminal is not supposed to
3671 support ANSI escape sequences. */
3673 __small_sprintf (tinfo
, "/usr/share/terminfo/%02x/%s", term
[0], term
);
3674 path_conv
path (tinfo
);
3676 path
.get_wide_win32_path (wtinfo
);
3678 h
= CreateFileW (wtinfo
, GENERIC_READ
, FILE_SHARE_READ
,
3679 NULL
, OPEN_EXISTING
, 0, NULL
);
3682 char terminfo
[4096];
3684 ReadFile (h
, terminfo
, sizeof (terminfo
), &n
, 0);
3688 if (*(int16_t *)terminfo
== 01036 /* MAGIC2 */)
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
)
3699 int str_idx_pos
= name_pos
+ name_size
+ bool_count
+ num_size
* num_count
;
3700 if (str_idx_pos
& 1)
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
))
3706 if (str_idx
[cursor_home
] == -1)
3708 const char *cursor_home_str
= str_table
+ str_idx
[cursor_home
];
3709 if (cursor_home_str
>= str_table
+ str_size
)
3711 if (cursor_home_str
>= terminfo
+ n
)
3713 if (strcmp (cursor_home_str
, "\033[H") != 0)
3719 fhandler_pty_slave::term_has_pcon_cap (const WCHAR
*env
)
3721 if (get_ttyp ()->pcon_cap_checked
)
3722 return get_ttyp ()->has_csi6n
;
3730 /* Check if terminal has ANSI escape sequence. */
3731 if (!has_ansi_escape_sequences (env
))
3734 /* Check if terminal has CSI6n */
3735 WaitForSingleObject (pipe_sw_mutex
, INFINITE
);
3736 WaitForSingleObject (input_mutex
, mutex_timeout
);
3737 /* Set pcon_activated and pcon_start so that the response
3738 will sent to io_handle_nat rather than io_handle. */
3739 get_ttyp ()->pcon_activated
= true;
3740 /* pcon_start will be cleared in master write() when CSI6n is responded. */
3741 get_ttyp ()->pcon_start
= true;
3742 WriteFile (get_output_handle (), "\033[6n", 4, &n
, NULL
);
3743 ReleaseMutex (input_mutex
);
3745 len
= sizeof (buf
) - 1;
3748 if (::bytes_available (n
, get_handle_nat ()) && n
)
3750 ReadFile (get_handle_nat (), p
, len
, &n
, NULL
);
3754 char *p1
= strrchr (buf
, '\033');
3757 if (p1
== NULL
|| sscanf (p1
, "\033[%d;%d%c", &y
, &x
, &c
) != 3
3763 else if (++wait_cnt
> 100) /* Timeout */
3769 get_ttyp ()->pcon_activated
= false;
3770 get_ttyp ()->nat_pipe_owner_pid
= 0;
3771 ReleaseMutex (pipe_sw_mutex
);
3775 get_ttyp ()->has_csi6n
= true;
3776 get_ttyp ()->pcon_cap_checked
= true;
3781 WaitForSingleObject (input_mutex
, mutex_timeout
);
3782 /* If CSI6n is not responded, pcon_start is not cleared
3783 in master write(). Therefore, clear it here manually. */
3784 get_ttyp ()->pcon_start
= false;
3785 get_ttyp ()->pcon_activated
= false;
3786 ReleaseMutex (input_mutex
);
3787 ReleaseMutex (pipe_sw_mutex
);
3789 get_ttyp ()->pcon_cap_checked
= true;
3794 fhandler_pty_slave::create_invisible_console ()
3796 if (get_ttyp ()->need_invisible_console
)
3798 /* Detach from console device and create new invisible console. */
3799 acquire_attach_mutex (mutex_timeout
);
3801 fhandler_console::need_invisible (true);
3802 init_console_handler (false);
3803 release_attach_mutex ();
3804 get_ttyp ()->need_invisible_console
= false;
3805 get_ttyp ()->invisible_console_pid
= myself
->pid
;
3807 if (get_ttyp ()->invisible_console_pid
3808 && !pinfo (get_ttyp ()->invisible_console_pid
))
3809 /* If primary slave process does not exist anymore,
3810 this process becomes the primary. */
3811 get_ttyp ()->invisible_console_pid
= myself
->pid
;
3815 fhandler_pty_master::get_master_thread_param (master_thread_param_t
*p
)
3817 p
->from_master_nat
= from_master_nat
;
3818 p
->from_master
= from_master
;
3819 p
->to_master_nat
= to_master_nat
;
3820 p
->to_master
= to_master
;
3821 p
->to_slave_nat
= to_slave_nat
;
3822 p
->to_slave
= get_output_handle ();
3823 p
->master_ctl
= master_ctl
;
3824 p
->input_available_event
= input_available_event
;
3825 SetEvent (thread_param_copied_event
);
3829 fhandler_pty_master::get_master_fwd_thread_param (master_fwd_thread_param_t
*p
)
3831 p
->to_master
= to_master
;
3832 p
->from_slave_nat
= from_slave_nat
;
3833 p
->output_mutex
= output_mutex
;
3834 p
->ttyp
= get_ttyp ();
3835 SetEvent (thread_param_copied_event
);
3838 #define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
3839 #define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
3841 fhandler_pty_slave::transfer_input (tty::xfer_dir dir
, HANDLE from
, tty
*ttyp
,
3842 HANDLE input_available_event
)
3845 if (dir
== tty::to_nat
)
3846 to
= ttyp
->to_slave_nat ();
3848 to
= ttyp
->to_slave ();
3850 pinfo
p (ttyp
->master_pid
);
3851 HANDLE pty_owner
= NULL
;
3853 pty_owner
= OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, p
->dwProcessId
);
3856 DuplicateHandle (pty_owner
, to
, GetCurrentProcess (), &to
,
3857 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3858 CloseHandle (pty_owner
);
3862 char pipe
[MAX_PATH
];
3863 __small_sprintf (pipe
,
3864 "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
3865 &cygheap
->installation_key
, ttyp
->get_minor ());
3866 pipe_request req
= { GetCurrentProcessId () };
3869 if (!CallNamedPipe (pipe
, &req
, sizeof req
,
3870 &repl
, sizeof repl
, &len
, 500))
3871 return; /* What can we do? */
3872 CloseHandle (repl
.from_master_nat
); /* not used. */
3873 CloseHandle (repl
.from_master
); /* not used. */
3874 CloseHandle (repl
.to_master_nat
); /* not used. */
3875 CloseHandle (repl
.to_master
); /* not used. */
3876 if (dir
== tty::to_nat
)
3878 CloseHandle (repl
.to_slave
); /* not used. */
3879 to
= repl
.to_slave_nat
;
3883 CloseHandle (repl
.to_slave_nat
); /* not used. */
3888 UINT cp_from
= 0, cp_to
= 0;
3890 if (dir
== tty::to_nat
)
3892 cp_from
= ttyp
->term_code_page
;
3893 if (ttyp
->pcon_activated
)
3896 cp_to
= GetConsoleCP ();
3900 cp_from
= GetConsoleCP ();
3901 cp_to
= ttyp
->term_code_page
;
3905 char *buf
= tp
.c_get ();
3907 bool transfered
= false;
3909 if (dir
== tty::to_cyg
&& ttyp
->pcon_activated
)
3910 { /* from handle is console handle */
3911 /* Reaches here for nat->cyg case with pcon activated. */
3912 INPUT_RECORD r
[INREC_SIZE
];
3914 while (PeekConsoleInputA (from
, r
, INREC_SIZE
, &n
) && n
)
3916 ReadConsoleInputA (from
, r
, n
, &n
);
3917 if (ttyp
->discard_input
)
3921 for (DWORD i
= 0; i
< n
; i
++)
3922 if (r
[i
].EventType
== KEY_EVENT
&& r
[i
].Event
.KeyEvent
.bKeyDown
)
3924 DWORD ctrl_key_state
= r
[i
].Event
.KeyEvent
.dwControlKeyState
;
3925 if (r
[i
].Event
.KeyEvent
.uChar
.AsciiChar
)
3927 if ((ctrl_key_state
& ALT_PRESSED
)
3928 && r
[i
].Event
.KeyEvent
.uChar
.AsciiChar
<= 0x7f)
3929 buf
[len
++] = '\033'; /* Meta */
3930 buf
[len
++] = r
[i
].Event
.KeyEvent
.uChar
.AsciiChar
;
3932 /* Allow Ctrl-Space to emit ^@ */
3933 else if (r
[i
].Event
.KeyEvent
.wVirtualKeyCode
== '2'
3934 && (ctrl_key_state
& CTRL_PRESSED
)
3935 && !(ctrl_key_state
& ALT_PRESSED
))
3938 { /* arrow/function keys */
3939 /* FIXME: The current code generates cygwin terminal
3940 sequence rather than xterm sequence. */
3943 fhandler_console::get_nonascii_key (r
[i
], tmp
);
3946 strcpy (buf
+ len
, add
);
3947 len
+= strlen (add
);
3951 if (cp_to
!= cp_from
)
3953 static mbstate_t mbp
;
3954 char *mbbuf
= tp
.c_get ();
3955 size_t nlen
= NT_MAX_PATH
;
3956 convert_mb_str (cp_to
, mbbuf
, &nlen
, cp_from
, buf
, len
, &mbp
);
3960 /* Call WriteFile() line by line */
3962 char *p_cr
= (char *) memchr (p0
, '\r', len
- (p0
- ptr
));
3963 char *p_lf
= (char *) memchr (p0
, '\n', len
- (p0
- ptr
));
3964 while (p_cr
|| p_lf
)
3967 p_cr
? (p_lf
? ((p_cr
+ 1 == p_lf
)
3968 ? p_lf
: min(p_cr
, p_lf
)) : p_cr
) : p_lf
;
3971 if (n
&& WriteFile (to
, p0
, n
, &n
, NULL
) && n
)
3974 p_cr
= (char *) memchr (p0
, '\r', len
- (p0
- ptr
));
3975 p_lf
= (char *) memchr (p0
, '\n', len
- (p0
- ptr
));
3977 n
= len
- (p0
- ptr
);
3978 if (n
&& WriteFile (to
, p0
, n
, &n
, NULL
) && n
)
3983 { /* Reaches here when both cyg->nat and nat->cyg cases with
3984 pcon not activated or cyg->nat case with pcon activated. */
3985 DWORD bytes_in_pipe
;
3986 while (::bytes_available (bytes_in_pipe
, from
) && bytes_in_pipe
)
3988 DWORD n
= MIN (bytes_in_pipe
, NT_MAX_PATH
);
3989 ReadFile (from
, buf
, n
, &n
, NULL
);
3990 if (ttyp
->discard_input
)
3993 if (dir
== tty::to_nat
)
3996 if (ttyp
->pcon_activated
)
3997 while ((p
= (char *) memchr (p
, '\n', n
- (p
- buf
))))
4000 while ((p
= (char *) memchr (p
, '\r', n
- (p
- buf
))))
4003 if (cp_to
!= cp_from
)
4005 static mbstate_t mbp
;
4006 char *mbbuf
= tp
.c_get ();
4007 size_t nlen
= NT_MAX_PATH
;
4008 convert_mb_str (cp_to
, mbbuf
, &nlen
, cp_from
, buf
, n
, &mbp
);
4012 if (n
&& WriteFile (to
, ptr
, n
, &n
, NULL
) && n
)
4018 /* Fix input_available_event which indicates availability in cyg pipe. */
4019 if (dir
== tty::to_nat
) /* all data is transfered to nat pipe,
4020 so no data available in cyg pipe. */
4021 ResetEvent (input_available_event
);
4022 else if (transfered
) /* There is data transfered to cyg pipe. */
4023 SetEvent (input_available_event
);
4024 ttyp
->pty_input_state
= dir
;
4025 ttyp
->discard_input
= false;
4029 fhandler_pty_slave::cleanup_before_exit ()
4031 if (myself
->process_state
& PID_NOTCYGWIN
)
4032 get_ttyp ()->wait_fwd ();
4036 fhandler_pty_slave::get_duplicated_handle_set (handle_set_t
*p
)
4038 DuplicateHandle (GetCurrentProcess (), get_handle_nat (),
4039 GetCurrentProcess (), &p
->from_master_nat
,
4040 0, 0, DUPLICATE_SAME_ACCESS
);
4041 DuplicateHandle (GetCurrentProcess (), input_available_event
,
4042 GetCurrentProcess (), &p
->input_available_event
,
4043 0, 0, DUPLICATE_SAME_ACCESS
);
4044 DuplicateHandle (GetCurrentProcess (), input_mutex
,
4045 GetCurrentProcess (), &p
->input_mutex
,
4046 0, 0, DUPLICATE_SAME_ACCESS
);
4047 DuplicateHandle (GetCurrentProcess (), pipe_sw_mutex
,
4048 GetCurrentProcess (), &p
->pipe_sw_mutex
,
4049 0, 0, DUPLICATE_SAME_ACCESS
);
4053 fhandler_pty_slave::close_handle_set (handle_set_t
*p
)
4055 CloseHandle (p
->from_master_nat
);
4056 p
->from_master_nat
= NULL
;
4057 CloseHandle (p
->input_available_event
);
4058 p
->input_available_event
= NULL
;
4059 CloseHandle (p
->input_mutex
);
4060 p
->input_mutex
= NULL
;
4061 CloseHandle (p
->pipe_sw_mutex
);
4062 p
->pipe_sw_mutex
= NULL
;
4066 fhandler_pty_slave::setup_for_non_cygwin_app (bool nopcon
,
4067 const WCHAR
*envblock
,
4070 if (disable_pcon
|| !term_has_pcon_cap (envblock
))
4072 WaitForSingleObject (pipe_sw_mutex
, INFINITE
);
4073 /* Setting switch_to_nat_pipe is necessary even if pseudo console
4074 will not be activated. */
4075 fhandler_base
*fh
= ::cygheap
->fdtab
[0];
4076 if (fh
&& fh
->get_major () == DEV_PTYS_MAJOR
)
4078 fhandler_pty_slave
*ptys
= (fhandler_pty_slave
*) fh
;
4079 ptys
->get_ttyp ()->switch_to_nat_pipe
= true;
4080 if (!process_alive (ptys
->get_ttyp ()->nat_pipe_owner_pid
))
4081 ptys
->get_ttyp ()->nat_pipe_owner_pid
= myself
->exec_dwProcessId
;
4083 bool pcon_enabled
= false;
4085 pcon_enabled
= setup_pseudoconsole ();
4086 ReleaseMutex (pipe_sw_mutex
);
4087 /* For pcon enabled case, transfer_input() is called in master::write() */
4088 if (!pcon_enabled
&& get_ttyp ()->getpgid () == myself
->pgid
4089 && stdin_is_ptys
&& get_ttyp ()->pty_input_state_eq (tty::to_cyg
))
4091 WaitForSingleObject (input_mutex
, mutex_timeout
);
4092 acquire_attach_mutex (mutex_timeout
);
4093 transfer_input (tty::to_nat
, get_handle (), get_ttyp (),
4094 input_available_event
);
4095 release_attach_mutex ();
4096 ReleaseMutex (input_mutex
);
4101 fhandler_pty_slave::cleanup_for_non_cygwin_app (handle_set_t
*p
, tty
*ttyp
,
4103 DWORD force_switch_to
)
4106 WaitForSingleObject (p
->pipe_sw_mutex
, INFINITE
);
4107 DWORD switch_to
= get_winpid_to_hand_over (ttyp
, force_switch_to
);
4108 if ((!switch_to
&& (ttyp
->pcon_activated
|| stdin_is_ptys
))
4109 && ttyp
->pty_input_state_eq (tty::to_nat
))
4111 WaitForSingleObject (p
->input_mutex
, mutex_timeout
);
4112 acquire_attach_mutex (mutex_timeout
);
4113 transfer_input (tty::to_cyg
, p
->from_master_nat
, ttyp
,
4114 p
->input_available_event
);
4115 release_attach_mutex ();
4116 ReleaseMutex (p
->input_mutex
);
4118 if (ttyp
->pcon_activated
)
4119 close_pseudoconsole (ttyp
, force_switch_to
);
4121 hand_over_only (ttyp
, force_switch_to
);
4122 ReleaseMutex (p
->pipe_sw_mutex
);
4126 fhandler_pty_slave::setpgid_aux (pid_t pid
)
4128 reset_switch_to_nat_pipe ();
4130 WaitForSingleObject (pipe_sw_mutex
, INFINITE
);
4131 bool was_nat_fg
= get_ttyp ()->nat_fg (tc ()->pgid
);
4132 bool nat_fg
= get_ttyp ()->nat_fg (pid
);
4133 if (!was_nat_fg
&& nat_fg
&& get_ttyp ()->switch_to_nat_pipe
4134 && get_ttyp ()->pty_input_state_eq (tty::to_cyg
))
4136 WaitForSingleObject (input_mutex
, mutex_timeout
);
4137 acquire_attach_mutex (mutex_timeout
);
4138 transfer_input (tty::to_nat
, get_handle (), get_ttyp (),
4139 input_available_event
);
4140 release_attach_mutex ();
4141 ReleaseMutex (input_mutex
);
4143 else if (was_nat_fg
&& !nat_fg
&& get_ttyp ()->switch_to_nat_pipe
4144 && get_ttyp ()->pty_input_state_eq (tty::to_nat
))
4146 bool attach_restore
= false;
4147 HANDLE from
= get_handle_nat ();
4148 DWORD resume_pid
= 0;
4149 WaitForSingleObject (input_mutex
, mutex_timeout
);
4150 if (get_ttyp ()->pcon_activated
&& get_ttyp ()->nat_pipe_owner_pid
4151 && !get_console_process_id (get_ttyp ()->nat_pipe_owner_pid
, true))
4153 HANDLE pcon_owner
= OpenProcess (PROCESS_DUP_HANDLE
, FALSE
,
4154 get_ttyp ()->nat_pipe_owner_pid
);
4155 DuplicateHandle (pcon_owner
, get_ttyp ()->h_pcon_in
,
4156 GetCurrentProcess (), &from
,
4157 0, TRUE
, DUPLICATE_SAME_ACCESS
);
4158 CloseHandle (pcon_owner
);
4159 DWORD target_pid
= get_ttyp ()->nat_pipe_owner_pid
;
4160 resume_pid
= attach_console_temporarily (target_pid
);
4161 attach_restore
= true;
4164 acquire_attach_mutex (mutex_timeout
);
4165 transfer_input (tty::to_cyg
, from
, get_ttyp (), input_available_event
);
4167 resume_from_temporarily_attach (resume_pid
);
4169 release_attach_mutex ();
4170 ReleaseMutex (input_mutex
);
4172 ReleaseMutex (pipe_sw_mutex
);
4176 fhandler_pty_master::need_send_ctrl_c_event ()
4178 /* If pseudo console is activated, sending CTRL_C_EVENT to non-cygwin
4179 apps will be done in pseudo console, therefore, sending it in
4180 fhandler_pty_master::write() duplicates that event for non-cygwin
4181 apps. So return false if pseudo console is activated. */
4182 return !(to_be_read_from_nat_pipe () && get_ttyp ()->pcon_activated
4183 && get_ttyp ()->pty_input_state
== tty::to_nat
);
4187 fhandler_pty_slave::release_ownership_of_nat_pipe (tty
*ttyp
,
4188 fhandler_termios
*fh
)
4190 if (fh
->get_major () == DEV_PTYM_MAJOR
4191 && nat_pipe_owner_self (ttyp
->nat_pipe_owner_pid
))
4193 fhandler_pty_master
*ptym
= (fhandler_pty_master
*) fh
;
4194 WaitForSingleObject (ptym
->pipe_sw_mutex
, INFINITE
);
4195 if (ttyp
->pcon_activated
)
4196 /* Do not acquire/release_attach_mutex() here because
4197 it has done in fhandler_termios::process_sigs(). */
4198 close_pseudoconsole (ttyp
);
4200 hand_over_only (ttyp
);
4201 ReleaseMutex (ptym
->pipe_sw_mutex
);
4206 fhandler_pty_common::attach_console_temporarily (DWORD target_pid
)
4208 DWORD resume_pid
= 0;
4209 acquire_attach_mutex (mutex_timeout
);
4210 pinfo
pinfo_resume (myself
->ppid
);
4212 resume_pid
= pinfo_resume
->dwProcessId
;
4214 resume_pid
= get_console_process_id (myself
->dwProcessId
, false);
4215 bool console_exists
= fhandler_console::exists ();
4216 if (!console_exists
|| resume_pid
)
4219 AttachConsole (target_pid
);
4220 init_console_handler (false);
4222 return console_exists
? resume_pid
: (DWORD
) -1;
4226 fhandler_pty_common::resume_from_temporarily_attach (DWORD resume_pid
)
4228 bool console_exists
= (resume_pid
!= (DWORD
) -1);
4229 if (!console_exists
|| resume_pid
)
4233 if (!resume_pid
|| !AttachConsole (resume_pid
))
4234 AttachConsole (ATTACH_PARENT_PROCESS
);
4235 init_console_handler (false);
4237 release_attach_mutex ();