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 DWORD mutex_timeout
; /* defined in fhandler_termios.cc */
38 extern "C" int sscanf (const char *, const char *, ...);
40 #define close_maybe(h) \
42 if (h && h != INVALID_HANDLE_VALUE) \
46 /* pty master control pipe messages */
52 HANDLE from_master_nat
;
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 pcon_pid_alive (DWORD pid
);
80 fhandler_pty_common::get_console_process_id (DWORD pid
, bool match
,
81 bool cygwin
, bool stub_only
)
84 DWORD
*list
= (DWORD
*) tp
.c_get ();
85 const DWORD buf_size
= NT_MAX_PATH
/ sizeof (DWORD
);
87 DWORD num
= GetConsoleProcessList (list
, buf_size
);
88 if (num
== 0 || num
> buf_size
)
91 DWORD res_pri
= 0, res
= 0;
92 /* Last one is the oldest. */
93 /* https://github.com/microsoft/terminal/issues/95 */
94 for (int i
= (int) num
- 1; i
>= 0; i
--)
95 if ((match
&& list
[i
] == pid
) || (!match
&& list
[i
] != pid
))
104 pinfo
p (cygwin_pid (list
[i
]));
105 if (!!p
&& p
->exec_dwProcessId
)
107 res_pri
= stub_only
? p
->exec_dwProcessId
: list
[i
];
110 if (!p
&& !res
&& pcon_pid_alive (list
[i
]) && stub_only
)
112 if (!!p
&& !res
&& !stub_only
)
116 return res_pri
?: res
;
119 static bool isHybrid
;
120 static HANDLE h_gdb_process
;
123 set_switch_to_pcon (HANDLE
*in
, HANDLE
*out
, HANDLE
*err
, bool iscygwin
)
125 cygheap_fdenum
cfd (false);
127 fhandler_base
*replace_in
= NULL
, *replace_out
= NULL
, *replace_err
= NULL
;
128 fhandler_pty_slave
*ptys_pcon
= NULL
;
129 while ((fd
= cfd
.next ()) >= 0)
131 if (*in
== cfd
->get_handle () ||
132 (fd
== 0 && *in
== GetStdHandle (STD_INPUT_HANDLE
)))
133 replace_in
= (fhandler_base
*) cfd
;
134 if (*out
== cfd
->get_output_handle () ||
135 (fd
== 1 && *out
== GetStdHandle (STD_OUTPUT_HANDLE
)))
136 replace_out
= (fhandler_base
*) cfd
;
137 if (*err
== cfd
->get_output_handle () ||
138 (fd
== 2 && *err
== GetStdHandle (STD_ERROR_HANDLE
)))
139 replace_err
= (fhandler_base
*) cfd
;
140 if (cfd
->get_device () == (dev_t
) myself
->ctty
)
142 fhandler_base
*fh
= cfd
;
143 fhandler_pty_slave
*ptys
= (fhandler_pty_slave
*) fh
;
144 if (*in
== ptys
->get_handle ()
145 || *out
== ptys
->get_output_handle ()
146 || *err
== ptys
->get_output_handle ())
150 if (!iscygwin
&& ptys_pcon
)
151 ptys_pcon
->set_switch_to_pcon ();
153 *in
= replace_in
->get_handle_nat ();
155 *out
= replace_out
->get_output_handle_nat ();
157 *err
= replace_err
->get_output_handle_nat ();
160 static bool atexit_func_registered
= false;
161 static bool debug_process
= false;
168 cygheap_fdenum
cfd (false);
169 while (cfd
.next () >= 0)
170 if (cfd
->get_device () == (dev_t
) myself
->ctty
)
172 DWORD force_switch_to
= 0;
173 if (WaitForSingleObject (h_gdb_process
, 0) == WAIT_TIMEOUT
175 force_switch_to
= GetProcessId (h_gdb_process
);
176 fhandler_base
*fh
= cfd
;
177 fhandler_pty_slave
*ptys
= (fhandler_pty_slave
*) fh
;
178 tty
*ttyp
= ptys
->get_ttyp ();
179 HANDLE from
= ptys
->get_handle_nat ();
180 HANDLE input_available_event
= ptys
->get_input_available_event ();
181 if (ttyp
->getpgid () == myself
->pgid
182 && GetStdHandle (STD_INPUT_HANDLE
) == ptys
->get_handle ()
183 && ttyp
->pcon_input_state_eq (tty::to_nat
) && !force_switch_to
)
185 WaitForSingleObject (ptys
->input_mutex
, mutex_timeout
);
186 fhandler_pty_slave::transfer_input (tty::to_cyg
, from
, ttyp
,
187 input_available_event
);
188 ReleaseMutex (ptys
->input_mutex
);
190 WaitForSingleObject (ptys
->pcon_mutex
, INFINITE
);
191 ptys
->close_pseudoconsole (ttyp
, force_switch_to
);
192 ReleaseMutex (ptys
->pcon_mutex
);
195 CloseHandle (h_gdb_process
);
199 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
200 /* CreateProcess() is hooked for GDB etc. */
201 DEF_HOOK (CreateProcessA
);
202 DEF_HOOK (CreateProcessW
);
205 CreateProcessA_Hooked
206 (LPCSTR n
, LPSTR c
, LPSECURITY_ATTRIBUTES pa
, LPSECURITY_ATTRIBUTES ta
,
207 BOOL inh
, DWORD f
, LPVOID e
, LPCSTR d
,
208 LPSTARTUPINFOA si
, LPPROCESS_INFORMATION pi
)
210 STARTUPINFOEXA siex
= {0, };
211 if (si
->cb
== sizeof (STARTUPINFOEXA
))
212 siex
= *(STARTUPINFOEXA
*)si
;
214 siex
.StartupInfo
= *si
;
215 STARTUPINFOA
*siov
= &siex
.StartupInfo
;
216 if (!(si
->dwFlags
& STARTF_USESTDHANDLES
))
218 siov
->dwFlags
|= STARTF_USESTDHANDLES
;
219 siov
->hStdInput
= GetStdHandle (STD_INPUT_HANDLE
);
220 siov
->hStdOutput
= GetStdHandle (STD_OUTPUT_HANDLE
);
221 siov
->hStdError
= GetStdHandle (STD_ERROR_HANDLE
);
225 char *prog
=tp
.c_get ();
227 __small_sprintf (prog
, "%s", n
);
230 __small_sprintf (prog
, "%s", c
);
234 if ((p1
= strchr (p
, ' ')) || (p1
= p
+ strlen (p
)))
240 find_exec (prog
, path
);
245 find_exec (prog
, path
);
247 while (!path
.exists() && *p
);
249 const char *argv
[] = {"", NULL
}; /* Dummy */
251 av1
.setup ("", path
, "", 1, argv
, false);
252 set_switch_to_pcon (&siov
->hStdInput
, &siov
->hStdOutput
, &siov
->hStdError
,
254 BOOL ret
= CreateProcessA_Orig (n
, c
, pa
, ta
, inh
, f
, e
, d
, siov
, pi
);
255 h_gdb_process
= pi
->hProcess
;
256 DuplicateHandle (GetCurrentProcess (), h_gdb_process
,
257 GetCurrentProcess (), &h_gdb_process
,
258 0, 0, DUPLICATE_SAME_ACCESS
);
259 debug_process
= !!(f
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
));
261 mutex_timeout
= 0; /* to avoid deadlock in GDB */
262 if (!atexit_func_registered
&& !path
.iscygexec ())
264 atexit (atexit_func
);
265 atexit_func_registered
= true;
271 CreateProcessW_Hooked
272 (LPCWSTR n
, LPWSTR c
, LPSECURITY_ATTRIBUTES pa
, LPSECURITY_ATTRIBUTES ta
,
273 BOOL inh
, DWORD f
, LPVOID e
, LPCWSTR d
,
274 LPSTARTUPINFOW si
, LPPROCESS_INFORMATION pi
)
276 STARTUPINFOEXW siex
= {0, };
277 if (si
->cb
== sizeof (STARTUPINFOEXW
))
278 siex
= *(STARTUPINFOEXW
*)si
;
280 siex
.StartupInfo
= *si
;
281 STARTUPINFOW
*siov
= &siex
.StartupInfo
;
282 if (!(si
->dwFlags
& STARTF_USESTDHANDLES
))
284 siov
->dwFlags
|= STARTF_USESTDHANDLES
;
285 siov
->hStdInput
= GetStdHandle (STD_INPUT_HANDLE
);
286 siov
->hStdOutput
= GetStdHandle (STD_OUTPUT_HANDLE
);
287 siov
->hStdError
= GetStdHandle (STD_ERROR_HANDLE
);
291 char *prog
=tp
.c_get ();
293 __small_sprintf (prog
, "%W", n
);
296 __small_sprintf (prog
, "%W", c
);
300 if ((p1
= strchr (p
, ' ')) || (p1
= p
+ strlen (p
)))
306 find_exec (prog
, path
);
311 find_exec (prog
, path
);
313 while (!path
.exists() && *p
);
315 const char *argv
[] = {"", NULL
}; /* Dummy */
317 av1
.setup ("", path
, "", 1, argv
, false);
318 set_switch_to_pcon (&siov
->hStdInput
, &siov
->hStdOutput
, &siov
->hStdError
,
320 BOOL ret
= CreateProcessW_Orig (n
, c
, pa
, ta
, inh
, f
, e
, d
, siov
, pi
);
321 h_gdb_process
= pi
->hProcess
;
322 DuplicateHandle (GetCurrentProcess (), h_gdb_process
,
323 GetCurrentProcess (), &h_gdb_process
,
324 0, 0, DUPLICATE_SAME_ACCESS
);
325 debug_process
= !!(f
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
));
327 mutex_timeout
= 0; /* to avoid deadlock in GDB */
328 if (!atexit_func_registered
&& !path
.iscygexec ())
330 atexit (atexit_func
);
331 atexit_func_registered
= true;
337 convert_mb_str (UINT cp_to
, char *ptr_to
, size_t *len_to
,
338 UINT cp_from
, const char *ptr_from
, size_t len_from
,
342 wchar_t *wbuf
= tp
.w_get ();
344 char *tmpbuf
= tp
.c_get ();
345 memcpy (tmpbuf
, mbp
->__value
.__wchb
, mbp
->__count
);
346 if (mbp
->__count
+ len_from
> NT_MAX_PATH
)
347 len_from
= NT_MAX_PATH
- mbp
->__count
;
348 memcpy (tmpbuf
+ mbp
->__count
, ptr_from
, len_from
);
349 int total_len
= mbp
->__count
+ len_from
;
352 for (const char *p
= tmpbuf
; p
< tmpbuf
+ total_len
; p
+= mblen
)
353 /* Max bytes in multibyte char supported is 4. */
354 for (mblen
= 1; mblen
<= 4; mblen
++)
357 int l
= MultiByteToWideChar (cp_from
, MB_ERR_INVALID_CHARS
,
359 wbuf
+ wlen
, NT_MAX_PATH
- wlen
);
361 { /* Conversion Success */
366 { /* Conversion Fail */
367 l
= MultiByteToWideChar (cp_from
, 0, p
, 1,
368 wbuf
+ wlen
, NT_MAX_PATH
- wlen
);
373 else if (p
+ mblen
== tmpbuf
+ total_len
)
374 { /* Multibyte char incomplete */
375 memcpy (mbp
->__value
.__wchb
, p
, mblen
);
376 mbp
->__count
= mblen
;
379 /* Retry conversion with extended length */
381 *len_to
= WideCharToMultiByte (cp_to
, 0, wbuf
, wlen
,
382 ptr_to
, *len_to
, NULL
, NULL
);
386 bytes_available (DWORD
& n
, HANDLE h
)
390 bool succeeded
= PeekNamedPipe (h
, NULL
, 0, NULL
, &navail
, &nleft
);
392 /* nleft should always be the right choice unless something has written 0
393 bytes to the pipe. In that pathological case we return the actual number
394 of bytes available in the pipe. See cgf-000008 for more details. */
398 termios_printf ("PeekNamedPipe(%p) failed, %E", h
);
401 debug_only_printf ("n %u, nleft %u, navail %u", n
, nleft
, navail
);
406 fhandler_pty_common::bytes_available (DWORD
&n
)
408 return ::bytes_available (n
, get_handle ());
412 static class mutex_stack
424 fhandler_pty_master::flush_to_slave ()
426 if (get_readahead_valid () && !(get_ttyp ()->ti
.c_lflag
& ICANON
))
431 fhandler_pty_master::discard_input ()
437 WaitForSingleObject (input_mutex
, mutex_timeout
);
438 while (::bytes_available (bytes_in_pipe
, from_master
) && bytes_in_pipe
)
439 ReadFile (from_master
, buf
, sizeof(buf
), &n
, NULL
);
440 ResetEvent (input_available_event
);
441 get_ttyp ()->discard_input
= true;
442 ReleaseMutex (input_mutex
);
446 fhandler_pty_common::__acquire_output_mutex (const char *fn
, int ln
,
449 if (strace
.active ())
450 strace
.prntf (_STRACE_TERMIOS
, fn
, "(%d): pty output_mutex (%p): waiting %d ms", ln
, output_mutex
, ms
);
451 DWORD res
= WaitForSingleObject (output_mutex
, ms
);
452 if (res
== WAIT_OBJECT_0
)
455 if (strace
.active ())
456 strace
.prntf (_STRACE_TERMIOS
, fn
, "(%d): pty output_mutex: acquired", ln
, res
);
460 ostack
[osi
].tname
= mythreadname ();
461 termios_printf ("acquired for %s:%d, osi %d", fn
, ln
, osi
);
469 fhandler_pty_common::__release_output_mutex (const char *fn
, int ln
)
471 if (ReleaseMutex (output_mutex
))
474 if (strace
.active ())
475 strace
.prntf (_STRACE_TERMIOS
, fn
, "(%d): pty output_mutex(%p) released", ln
, output_mutex
);
479 termios_printf ("released(%p) at %s:%d, osi %d", output_mutex
, fn
, ln
, osi
);
480 termios_printf (" for %s:%d (%s)", ostack
[osi
].fn
, ostack
[osi
].ln
, ostack
[osi
].tname
);
481 ostack
[osi
].ln
= -ln
;
487 system_printf ("couldn't release output mutex but we seem to own it, %E");
493 /* Process pty input. */
496 fhandler_pty_master::doecho (const void *str
, DWORD len
)
498 ssize_t towrite
= len
;
499 acquire_output_mutex (mutex_timeout
);
500 if (!process_opost_output (echo_w
, str
, towrite
, true,
501 get_ttyp (), is_nonblocking ()))
502 termios_printf ("Write to echo pipe failed, %E");
503 release_output_mutex ();
507 fhandler_pty_master::accept_input ()
512 WaitForSingleObject (input_mutex
, mutex_timeout
);
514 char *p
= rabuf () + raixget ();
515 bytes_left
= eat_readahead (-1);
517 HANDLE write_to
= get_output_handle ();
519 if (to_be_read_from_pcon ()
520 && get_ttyp ()->pcon_input_state
== tty::to_nat
)
522 write_to
= to_slave_nat
;
525 pinfo pinfo_target
= pinfo (get_ttyp ()->invisible_console_pid
);
526 DWORD target_pid
= 0;
528 target_pid
= pinfo_target
->dwProcessId
;
529 pinfo pinfo_resume
= pinfo (myself
->ppid
);
532 resume_pid
= pinfo_resume
->dwProcessId
;
534 resume_pid
= get_console_process_id (myself
->dwProcessId
, false);
535 if (target_pid
&& resume_pid
)
537 /* Slave attaches to a different console than master.
538 Therefore reattach here. */
539 acquire_attach_mutex (mutex_timeout
);
541 AttachConsole (target_pid
);
542 cp_to
= GetConsoleCP ();
544 AttachConsole (resume_pid
);
545 release_attach_mutex ();
548 cp_to
= GetConsoleCP ();
550 if (get_ttyp ()->term_code_page
!= cp_to
)
552 static mbstate_t mbp
;
553 char *mbbuf
= tp
.c_get ();
554 size_t nlen
= NT_MAX_PATH
;
555 convert_mb_str (cp_to
, mbbuf
, &nlen
,
556 get_ttyp ()->term_code_page
, p
, bytes_left
, &mbp
);
564 termios_printf ("sending EOF to slave");
565 get_ttyp ()->read_retval
= 0;
572 paranoid_printf ("about to write %u chars to slave", bytes_left
);
573 /* Write line by line for transfer input. */
577 while ((p1
= (char *) memchr (p0
, '\n', bytes_left
- (p0
- p
)))
578 || (p1
= (char *) memchr (p0
, '\r', bytes_left
- (p0
- p
))))
581 rc
= WriteFile (write_to
, p0
, n
, &n
, NULL
);
586 if (rc
&& (n
= bytes_left
- (p0
- p
)))
588 rc
= WriteFile (write_to
, p0
, n
, &n
, NULL
);
592 if (!rc
&& written
== 0)
594 debug_printf ("error writing to pipe %p %E", write_to
);
595 get_ttyp ()->read_retval
= -1;
596 puts_readahead (p
, bytes_left
);
601 get_ttyp ()->read_retval
= 1;
603 bytes_left
-= written
;
606 debug_printf ("to_slave pipe is full");
607 puts_readahead (p
, bytes_left
);
613 if (write_to
== get_output_handle ())
614 SetEvent (input_available_event
);
615 ReleaseMutex (input_mutex
);
620 fhandler_pty_master::hit_eof ()
622 if (get_ttyp ()->was_opened
&& !get_ttyp ()->slave_alive ())
624 /* We have the only remaining open handle to this pty, and
625 the slave pty has been opened at least once. We treat
627 termios_printf ("all other handles closed");
633 /* Process pty output requests */
636 fhandler_pty_master::process_slave_output (char *buf
, size_t len
, int pktmode_on
)
639 char outbuf
[OUT_BUFFER_SIZE
];
654 /* Check echo pipe first. */
655 if (::bytes_available (echo_cnt
, echo_r
) && echo_cnt
> 0)
657 if (!bytes_available (n
))
667 /* tclush can finish here. */
671 if (is_nonblocking ())
677 pthread_testcancel ();
678 if (cygwait (NULL
, 10, cw_sig_eintr
) == WAIT_SIGNALED
679 && !_my_tls
.call_signal_handler ())
688 /* Set RLEN to the number of bytes to read from the pipe. */
693 if (pktmode_on
&& buf
)
695 *optr
++ = TIOCPKT_DATA
;
705 if (rlen
> sizeof outbuf
)
706 rlen
= sizeof outbuf
;
708 /* If echo pipe has data (something has been typed or pasted), prefer
709 it over slave output. */
712 if (!ReadFile (echo_r
, outbuf
, rlen
, &n
, NULL
))
714 termios_printf ("ReadFile on echo pipe failed, %E");
718 else if (!ReadFile (get_handle (), outbuf
, rlen
, &n
, NULL
))
720 termios_printf ("ReadFile failed, %E");
724 termios_printf ("bytes read %u", n
);
726 if (!buf
|| ((get_ttyp ()->ti
.c_lflag
& FLUSHO
)
727 && !get_ttyp ()->mask_flusho
))
728 continue; /* Discard read data */
730 memcpy (optr
, outbuf
, n
);
736 if (GetLastError () == ERROR_BROKEN_PIPE
)
748 set_mask_flusho (false);
749 termios_printf ("returning %d", rc
);
753 /* pty slave stuff */
755 fhandler_pty_slave::fhandler_pty_slave (int unit
)
756 : fhandler_pty_common (), inuse (NULL
), output_handle_nat (NULL
),
757 io_handle_nat (NULL
), slave_reading (NULL
), num_reader (0)
760 dev ().parse (DEV_PTYS_MAJOR
, unit
);
764 fhandler_pty_slave::open (int flags
, mode_t
)
767 HANDLE from_master_nat_local
, from_master_local
;
768 HANDLE to_master_nat_local
, to_master_local
;
771 &from_master_nat_local
, &input_available_event
, &input_mutex
, &inuse
,
772 &output_mutex
, &to_master_nat_local
, &pty_owner
, &to_master_local
,
773 &from_master_local
, &pcon_mutex
,
777 for (HANDLE
**h
= handles
; *h
; h
++)
780 _tc
= cygwin_shared
->tty
[get_minor ()];
784 cygwin_shared
->tty
.attach (get_minor ());
786 /* Create synchronisation events */
789 const char *errmsg
= NULL
;
791 if (!(output_mutex
= get_ttyp ()->open_output_mutex (MAXIMUM_ALLOWED
)))
793 errmsg
= "open output mutex failed, %E";
796 if (!(input_mutex
= get_ttyp ()->open_input_mutex (MAXIMUM_ALLOWED
)))
798 errmsg
= "open input mutex failed, %E";
801 if (!(pcon_mutex
= get_ttyp ()->open_mutex (PCON_MUTEX
, MAXIMUM_ALLOWED
)))
803 errmsg
= "open pcon mutex failed, %E";
806 shared_name (buf
, INPUT_AVAILABLE_EVENT
, get_minor ());
807 if (!(input_available_event
= OpenEvent (MAXIMUM_ALLOWED
, TRUE
, buf
)))
809 errmsg
= "open input event failed, %E";
813 /* FIXME: Needs a method to eliminate tty races */
815 /* Create security attribute. Default permissions are 0620. */
816 security_descriptor sd
;
817 sd
.malloc (sizeof (SECURITY_DESCRIPTOR
));
818 RtlCreateSecurityDescriptor (sd
, SECURITY_DESCRIPTOR_REVISION
);
819 SECURITY_ATTRIBUTES sa
= { sizeof (SECURITY_ATTRIBUTES
), NULL
, TRUE
};
820 if (!create_object_sd_from_attribute (myself
->uid
, myself
->gid
,
821 S_IFCHR
| S_IRUSR
| S_IWUSR
| S_IWGRP
,
823 sa
.lpSecurityDescriptor
= (PSECURITY_DESCRIPTOR
) sd
;
824 acquire_output_mutex (mutex_timeout
);
825 inuse
= get_ttyp ()->create_inuse (&sa
);
826 get_ttyp ()->was_opened
= true;
827 release_output_mutex ();
830 if (!get_ttyp ()->from_master_nat () || !get_ttyp ()->from_master ()
831 || !get_ttyp ()->to_master_nat () || !get_ttyp ()->to_master ())
833 errmsg
= "pty handles have been closed";
838 /* Three case for duplicating the pipe handles:
839 - Either we're the master. In this case, just duplicate the handles.
840 - Or, we have the right to open the master process for handle duplication.
841 In this case, just duplicate the handles.
842 - Or, we have to ask the master process itself. In this case, send our
843 pid to the master process and check the reply. The reply contains
844 either the handles, or an error code which tells us why we didn't
846 if (myself
->pid
== get_ttyp ()->master_pid
)
848 /* This is the most common case, just calling openpty. */
849 termios_printf ("dup handles within myself.");
850 pty_owner
= GetCurrentProcess ();
854 pinfo
p (get_ttyp ()->master_pid
);
856 termios_printf ("*** couldn't find pty master");
859 pty_owner
= OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, p
->dwProcessId
);
861 termios_printf ("dup handles directly since I'm the owner");
866 if (!DuplicateHandle (pty_owner
, get_ttyp ()->from_master_nat (),
867 GetCurrentProcess (),
868 &from_master_nat_local
, 0, TRUE
,
869 DUPLICATE_SAME_ACCESS
))
871 termios_printf ("can't duplicate input from %u/%p, %E",
872 get_ttyp ()->master_pid
,
873 get_ttyp ()->from_master_nat ());
877 if (!DuplicateHandle (pty_owner
, get_ttyp ()->from_master (),
878 GetCurrentProcess (),
879 &from_master_local
, 0, TRUE
,
880 DUPLICATE_SAME_ACCESS
))
882 termios_printf ("can't duplicate input from %u/%p, %E",
883 get_ttyp ()->master_pid
,
884 get_ttyp ()->from_master ());
888 if (!DuplicateHandle (pty_owner
, get_ttyp ()->to_master_nat (),
889 GetCurrentProcess (),
890 &to_master_nat_local
, 0, TRUE
,
891 DUPLICATE_SAME_ACCESS
))
893 errmsg
= "can't duplicate output, %E";
896 if (!DuplicateHandle (pty_owner
, get_ttyp ()->to_master (),
897 GetCurrentProcess (),
898 &to_master_local
, 0, TRUE
,
899 DUPLICATE_SAME_ACCESS
))
901 errmsg
= "can't duplicate output for cygwin, %E";
904 if (pty_owner
!= GetCurrentProcess ())
905 CloseHandle (pty_owner
);
909 pipe_request req
= { GetCurrentProcessId () };
913 __small_sprintf (buf
, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
914 &cygheap
->installation_key
, get_minor ());
915 termios_printf ("dup handles via master control pipe %s", buf
);
916 if (!CallNamedPipe (buf
, &req
, sizeof req
, &repl
, sizeof repl
,
919 errmsg
= "can't call master, %E";
922 from_master_nat_local
= repl
.from_master_nat
;
923 from_master_local
= repl
.from_master
;
924 to_master_nat_local
= repl
.to_master_nat
;
925 to_master_local
= repl
.to_master
;
926 if (!from_master_nat_local
|| !from_master_local
927 || !to_master_nat_local
|| !to_master_local
)
929 SetLastError (repl
.error
);
930 errmsg
= "error duplicating pipes, %E";
934 VerifyHandle (from_master_nat_local
);
935 VerifyHandle (from_master_local
);
936 VerifyHandle (to_master_nat_local
);
937 VerifyHandle (to_master_local
);
939 termios_printf ("duplicated from_master_nat %p->%p from pty_owner",
940 get_ttyp ()->from_master_nat (), from_master_nat_local
);
941 termios_printf ("duplicated from_master %p->%p from pty_owner",
942 get_ttyp ()->from_master (), from_master_local
);
943 termios_printf ("duplicated to_master_nat %p->%p from pty_owner",
944 get_ttyp ()->to_master_nat (), to_master_nat_local
);
945 termios_printf ("duplicated to_master %p->%p from pty_owner",
946 get_ttyp ()->to_master (), to_master_local
);
948 set_handle_nat (from_master_nat_local
);
949 set_handle (from_master_local
);
950 set_output_handle_nat (to_master_nat_local
);
951 set_output_handle (to_master_local
);
953 if (_major (myself
->ctty
) == DEV_CONS_MAJOR
954 && !(!pinfo (myself
->ppid
) && getenv ("ConEmuPID")))
955 /* This process is supposed to be a master process which is
956 running on console. Invisible console will be created in
957 primary slave process to prevent overriding code page
958 of root console by setup_locale(). */
959 /* ... except for ConEmu cygwin-connector in which this
960 code does not work as expected because it calls Win32
961 API directly rather than cygwin read()/write(). Due to
962 this behaviour, protection based on attach_mutex does
964 get_ttyp ()->need_invisible_console
= true;
966 fhandler_console::need_invisible ();
972 if (GetLastError () == ERROR_FILE_NOT_FOUND
)
977 termios_printf (errmsg
);
979 for (HANDLE
**h
= handles
; *h
; h
++)
980 if (**h
&& **h
!= INVALID_HANDLE_VALUE
)
986 fhandler_pty_slave::open_setup (int flags
)
988 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
989 myself
->set_ctty (this, flags
);
990 report_tty_counts (this, "opened", "");
991 return fhandler_base::open_setup (flags
);
995 fhandler_pty_slave::cleanup ()
997 /* This used to always call fhandler_pty_common::close when we were execing
998 but that caused multiple closes of the handles associated with this pty.
999 Since close_all_files is not called until after the cygwin process has
1000 synced or before a non-cygwin process has exited, it should be safe to
1001 just close this normally. cgf 2006-05-20 */
1002 report_tty_counts (this, "closed", "");
1003 fhandler_base::cleanup ();
1007 fhandler_pty_slave::close ()
1009 termios_printf ("closing last open %s handle", ttyname ());
1010 if (inuse
&& !CloseHandle (inuse
))
1011 termios_printf ("CloseHandle (inuse), %E");
1012 if (!ForceCloseHandle (input_available_event
))
1013 termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event
);
1014 if (!ForceCloseHandle (get_output_handle_nat ()))
1015 termios_printf ("CloseHandle (get_output_handle_nat ()<%p>), %E",
1016 get_output_handle_nat ());
1017 if (!ForceCloseHandle (get_handle_nat ()))
1018 termios_printf ("CloseHandle (get_handle_nat ()<%p>), %E",
1020 if ((unsigned) myself
->ctty
== FHDEV (DEV_PTYS_MAJOR
, get_minor ()))
1021 fhandler_console::free_console (); /* assumes that we are the last pty closer */
1022 fhandler_pty_common::close ();
1023 if (!ForceCloseHandle (output_mutex
))
1024 termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex
);
1029 fhandler_pty_slave::init (HANDLE h
, DWORD a
, mode_t
)
1033 a
&= GENERIC_READ
| GENERIC_WRITE
;
1034 if (a
== GENERIC_READ
)
1036 if (a
== GENERIC_WRITE
)
1038 if (a
== (GENERIC_READ
| GENERIC_WRITE
))
1041 int ret
= open_with_arch (flags
);
1043 if (ret
&& !cygwin_finished_initializing
&& !being_debugged ())
1045 /* This only occurs when called from dtable::init_std_file_from_handle
1046 We have been started from a non-Cygwin process. So we should become
1047 pty process group leader.
1048 TODO: Investigate how SIGTTIN should be handled with pure-windows
1050 pinfo
p (tc ()->getpgid ());
1051 /* We should only grab this when the process group owner for this
1052 pty is a non-cygwin process or we've been started directly
1053 from a non-Cygwin process with no Cygwin ancestry. */
1054 if (!p
|| ISSTATE (p
, PID_NOTCYGWIN
))
1056 termios_printf ("Setting process group leader to %d since %W(%d) is not a cygwin process",
1057 myself
->pgid
, p
->progname
, p
->pid
);
1058 tc ()->setpgid (myself
->pgid
);
1062 if (h
!= INVALID_HANDLE_VALUE
)
1063 CloseHandle (h
); /* Reopened by open */
1069 fhandler_pty_slave::set_switch_to_pcon (void)
1075 myself
->exec_dwProcessId
= myself
->dwProcessId
;
1076 myself
->process_state
|= PID_NEW_PG
; /* Marker for pcon_fg */
1077 bool nopcon
= (disable_pcon
|| !term_has_pcon_cap (NULL
));
1078 WaitForSingleObject (pcon_mutex
, INFINITE
);
1079 bool pcon_enabled
= setup_pseudoconsole (nopcon
);
1080 ReleaseMutex (pcon_mutex
);
1081 if (!pcon_enabled
&& get_ttyp ()->getpgid () == myself
->pgid
1082 && GetStdHandle (STD_INPUT_HANDLE
) == get_handle ()
1083 && get_ttyp ()->pcon_input_state_eq (tty::to_cyg
))
1085 WaitForSingleObject (input_mutex
, mutex_timeout
);
1086 transfer_input (tty::to_nat
, get_handle (), get_ttyp (),
1087 input_available_event
);
1088 ReleaseMutex (input_mutex
);
1094 pcon_pid_alive (DWORD pid
)
1098 HANDLE h
= OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, pid
);
1102 BOOL r
= GetExitCodeProcess (h
, &exit_code
);
1104 if (r
&& exit_code
== STILL_ACTIVE
)
1110 pcon_pid_self (DWORD pid
)
1112 return (pid
== myself
->exec_dwProcessId
);
1116 fhandler_pty_slave::reset_switch_to_pcon (void)
1120 if (WaitForSingleObject (h_gdb_process
, 0) == WAIT_TIMEOUT
)
1123 get_ttyp ()->wait_pcon_fwd (false);
1127 CloseHandle (h_gdb_process
);
1128 h_gdb_process
= NULL
;
1129 mutex_timeout
= INFINITE
;
1132 if (get_ttyp ()->getpgid () == myself
->pgid
1133 && GetStdHandle (STD_INPUT_HANDLE
) == get_handle ()
1134 && get_ttyp ()->pcon_input_state_eq (tty::to_nat
))
1136 WaitForSingleObject (input_mutex
, mutex_timeout
);
1137 transfer_input (tty::to_cyg
, get_handle_nat (), get_ttyp (),
1138 input_available_event
);
1139 ReleaseMutex (input_mutex
);
1141 if (get_ttyp ()->master_is_running_as_service
1142 && get_ttyp ()->pcon_activated
)
1143 /* If the master is running as service, re-attaching to
1144 the console of the parent process will fail.
1145 Therefore, never close pseudo console here. */
1147 bool need_restore_handles
= get_ttyp ()->pcon_activated
;
1148 WaitForSingleObject (pcon_mutex
, INFINITE
);
1149 close_pseudoconsole (get_ttyp ());
1150 ReleaseMutex (pcon_mutex
);
1151 if (need_restore_handles
)
1153 pinfo
p (get_ttyp ()->master_pid
);
1155 OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, p
->dwProcessId
);
1158 CloseHandle (get_handle_nat ());
1159 DuplicateHandle (pty_owner
,
1160 get_ttyp ()->from_master_nat (),
1161 GetCurrentProcess (), &get_handle_nat (),
1162 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1163 CloseHandle (get_output_handle_nat ());
1164 DuplicateHandle (pty_owner
,
1165 get_ttyp ()->to_master_nat (),
1166 GetCurrentProcess (),
1167 &get_output_handle_nat (),
1168 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1169 CloseHandle (pty_owner
);
1173 char pipe
[MAX_PATH
];
1174 __small_sprintf (pipe
,
1175 "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
1176 &cygheap
->installation_key
, get_minor ());
1177 pipe_request req
= { GetCurrentProcessId () };
1180 if (!CallNamedPipe (pipe
, &req
, sizeof req
,
1181 &repl
, sizeof repl
, &len
, 500))
1182 return; /* What can we do? */
1183 CloseHandle (get_handle_nat ());
1184 set_handle_nat (repl
.from_master_nat
);
1185 CloseHandle (get_output_handle_nat ());
1186 set_output_handle_nat (repl
.to_master_nat
);
1189 myself
->exec_dwProcessId
= 0;
1190 myself
->process_state
&= ~PID_NEW_PG
;
1197 if (get_ttyp ()->pcon_start
)
1199 DWORD wait_ret
= WaitForSingleObject (pcon_mutex
, mutex_timeout
);
1200 if (wait_ret
== WAIT_TIMEOUT
)
1202 if (!pcon_pid_self (get_ttyp ()->pcon_pid
)
1203 && pcon_pid_alive (get_ttyp ()->pcon_pid
))
1205 /* There is a process which is grabbing pseudo console. */
1206 if (!to_be_read_from_pcon ()
1207 && get_ttyp ()->pcon_input_state_eq (tty::to_nat
))
1209 if (get_ttyp ()->pcon_activated
)
1212 OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, get_ttyp ()->pcon_pid
);
1215 pinfo pinfo_resume
= pinfo (myself
->ppid
);
1218 resume_pid
= pinfo_resume
->dwProcessId
;
1221 get_console_process_id (myself
->dwProcessId
, false);
1225 DuplicateHandle (pcon_owner
, get_ttyp ()->h_pcon_in
,
1226 GetCurrentProcess (), &h_pcon_in
,
1227 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1229 AttachConsole (get_ttyp ()->pcon_pid
);
1230 WaitForSingleObject (input_mutex
, mutex_timeout
);
1231 transfer_input (tty::to_cyg
, h_pcon_in
, get_ttyp (),
1232 input_available_event
);
1233 ReleaseMutex (input_mutex
);
1235 AttachConsole (resume_pid
);
1236 CloseHandle (h_pcon_in
);
1238 CloseHandle (pcon_owner
);
1241 else if (!get_ttyp ()->pcon_fg (get_ttyp ()->getpgid ())
1242 && get_ttyp ()->switch_to_pcon_in
)
1244 WaitForSingleObject (input_mutex
, mutex_timeout
);
1245 transfer_input (tty::to_cyg
, get_handle_nat (), get_ttyp (),
1246 input_available_event
);
1247 ReleaseMutex (input_mutex
);
1250 ReleaseMutex (pcon_mutex
);
1253 /* This input transfer is needed if non-cygwin app is terminated
1254 by Ctrl-C or killed. */
1255 WaitForSingleObject (input_mutex
, mutex_timeout
);
1256 if (get_ttyp ()->switch_to_pcon_in
&& !get_ttyp ()->pcon_activated
1257 && get_ttyp ()->pcon_input_state_eq (tty::to_nat
))
1258 transfer_input (tty::to_cyg
, get_handle_nat (), get_ttyp (),
1259 input_available_event
);
1260 ReleaseMutex (input_mutex
);
1261 get_ttyp ()->pcon_input_state
= tty::to_cyg
;
1262 get_ttyp ()->pcon_pid
= 0;
1263 get_ttyp ()->switch_to_pcon_in
= false;
1264 get_ttyp ()->pcon_activated
= false;
1265 ReleaseMutex (pcon_mutex
);
1269 fhandler_pty_slave::write (const void *ptr
, size_t len
)
1271 ssize_t towrite
= len
;
1273 bg_check_types bg
= bg_check (SIGTTOU
);
1275 return (ssize_t
) bg
;
1277 termios_printf ("pty%d, write(%p, %lu)", get_minor (), ptr
, len
);
1279 push_process_state
process_state (PID_TTYOU
);
1281 reset_switch_to_pcon ();
1283 acquire_output_mutex (mutex_timeout
);
1284 if (!process_opost_output (get_output_handle (), ptr
, towrite
, false,
1285 get_ttyp (), is_nonblocking ()))
1287 DWORD err
= GetLastError ();
1288 termios_printf ("WriteFile failed, %E");
1292 err
= ERROR_IO_DEVICE
;
1295 __seterrno_from_win_error (err
);
1299 release_output_mutex ();
1305 fhandler_pty_slave::mask_switch_to_pcon_in (bool mask
, bool xfer
)
1307 char name
[MAX_PATH
];
1308 shared_name (name
, TTY_SLAVE_READING
, get_minor ());
1309 HANDLE masked
= OpenEvent (READ_CONTROL
, FALSE
, name
);
1310 CloseHandle (masked
);
1312 WaitForSingleObject (input_mutex
, mutex_timeout
);
1315 if (InterlockedIncrement (&num_reader
) == 1)
1316 slave_reading
= CreateEvent (&sec_none_nih
, TRUE
, FALSE
, name
);
1318 else if (InterlockedDecrement (&num_reader
) == 0)
1319 CloseHandle (slave_reading
);
1321 /* This is needed when cygwin-app is started from non-cygwin app if
1322 pseudo console is disabled. */
1323 bool need_xfer
= get_ttyp ()->pcon_fg (get_ttyp ()->getpgid ())
1324 && get_ttyp ()->switch_to_pcon_in
&& !get_ttyp ()->pcon_activated
;
1326 /* In GDB, transfer input based on setpgid() does not work because
1327 GDB may not set terminal process group properly. Therefore,
1328 transfer input here if isHybrid is set. */
1329 bool need_gdb_xfer
=
1330 isHybrid
&& GetStdHandle (STD_INPUT_HANDLE
) == get_handle ();
1331 if (!!masked
!= mask
&& xfer
&& (need_gdb_xfer
|| need_xfer
))
1333 if (mask
&& get_ttyp ()->pcon_input_state_eq (tty::to_nat
))
1334 transfer_input (tty::to_cyg
, get_handle_nat (), get_ttyp (),
1335 input_available_event
);
1336 else if (!mask
&& get_ttyp ()->pcon_input_state_eq (tty::to_cyg
))
1337 transfer_input (tty::to_nat
, get_handle (), get_ttyp (),
1338 input_available_event
);
1340 ReleaseMutex (input_mutex
);
1344 fhandler_pty_common::to_be_read_from_pcon (void)
1346 if (!get_ttyp ()->switch_to_pcon_in
)
1349 char name
[MAX_PATH
];
1350 shared_name (name
, TTY_SLAVE_READING
, get_minor ());
1351 HANDLE masked
= OpenEvent (READ_CONTROL
, FALSE
, name
);
1352 CloseHandle (masked
);
1354 if (masked
) /* The foreground process is cygwin process */
1357 if (!pinfo (get_ttyp ()->getpgid ()))
1358 /* GDB may set invalid process group for non-cygwin process. */
1361 return get_ttyp ()->pcon_fg (get_ttyp ()->getpgid ());
1365 fhandler_pty_slave::read (void *ptr
, size_t& len
)
1367 ssize_t totalread
= 0;
1369 int vtime
= 0; /* Initialized to prevent -Wuninitialized warning */
1371 DWORD bytes_in_pipe
;
1372 char buf
[INP_BUFFER_SIZE
];
1374 char *ptr0
= (char *) ptr
;
1376 bg_check_types bg
= bg_check (SIGTTIN
);
1383 termios_printf ("read(%p, %lu) handle %p", ptr
, len
, get_handle ());
1385 push_process_state
process_state (PID_TTYIN
);
1387 if (ptr
) /* Indicating not tcflush(). */
1389 mask_switch_to_pcon_in (true, true);
1390 reset_switch_to_pcon ();
1393 if (is_nonblocking () || !ptr
) /* Indicating tcflush(). */
1395 else if ((get_ttyp ()->ti
.c_lflag
& ICANON
))
1396 time_to_wait
= INFINITE
;
1399 vmin
= get_ttyp ()->ti
.c_cc
[VMIN
];
1400 if (vmin
> INP_BUFFER_SIZE
)
1401 vmin
= INP_BUFFER_SIZE
;
1402 vtime
= get_ttyp ()->ti
.c_cc
[VTIME
];
1407 if (!vmin
&& !vtime
)
1410 time_to_wait
= !vtime
? INFINITE
: 100 * vtime
;
1416 switch (cygwait (input_available_event
, time_to_wait
))
1423 termios_printf ("wait catched signal");
1424 set_sig_errno (EINTR
);
1428 process_state
.pop ();
1429 pthread::static_cancel_self ();
1432 termios_printf ("wait timed out, time_to_wait %u", time_to_wait
);
1433 /* No error condition when called from tcflush. */
1434 if (!totalread
&& ptr
)
1436 set_sig_errno (EAGAIN
);
1441 termios_printf ("wait for input event failed, %E");
1449 /* Now that we know that input is available we have to grab the
1451 switch (cygwait (input_mutex
, 1000))
1454 case WAIT_ABANDONED_0
:
1459 termios_printf ("wait for mutex caught signal");
1460 set_sig_errno (EINTR
);
1464 process_state
.pop ();
1465 pthread::static_cancel_self ();
1468 termios_printf ("failed to acquire input mutex after input event "
1470 /* If we have a timeout, we can simply handle this failure to
1471 grab the mutex as an EAGAIN situation. Otherwise, if this
1472 is an infinitely blocking read, restart the loop. */
1473 if (time_to_wait
!= INFINITE
)
1477 set_sig_errno (EAGAIN
);
1484 termios_printf ("wait for input mutex failed, %E");
1492 if (!IsEventSignalled (input_available_event
))
1493 { /* Maybe another thread has processed input. */
1494 ReleaseMutex (input_mutex
);
1498 if (!bytes_available (bytes_in_pipe
))
1500 ReleaseMutex (input_mutex
);
1506 if (ptr
&& !bytes_in_pipe
&& !vmin
&& !time_to_wait
)
1508 ReleaseMutex (input_mutex
);
1509 mask_switch_to_pcon_in (false, false);
1510 len
= (size_t) bytes_in_pipe
;
1514 readlen
= bytes_in_pipe
? MIN (len
, sizeof (buf
)) : 0;
1515 if (get_ttyp ()->ti
.c_lflag
& ICANON
&& ptr
)
1516 readlen
= MIN (bytes_in_pipe
, readlen
);
1519 /* Why on earth is the read length reduced to vmin, even if more bytes
1520 are available *and* len is bigger *and* the local buf is big enough?
1521 Disable this code for now, it looks like a remnant of old. */
1522 if (ptr
&& vmin
&& readlen
> (unsigned) vmin
)
1529 termios_printf ("reading %lu bytes (vtime %d)", readlen
, vtime
);
1530 if (!ReadFile (get_handle (), buf
, readlen
, &n
, NULL
))
1532 termios_printf ("read failed, %E");
1533 ReleaseMutex (input_mutex
);
1540 /* MSDN states that 5th prameter can be used to determine total
1541 number of bytes in pipe, but for some reason this number doesn't
1542 change after successful read. So we have to peek into the pipe
1543 again to see if input is still available */
1544 if (!bytes_available (bytes_in_pipe
))
1546 ReleaseMutex (input_mutex
);
1553 if (!(!ptr
&& len
== UINT_MAX
)) /* not tcflush() */
1558 memcpy (ptr
, buf
, n
);
1559 ptr
= (char *) ptr
+ n
;
1566 ResetEvent (input_available_event
);
1568 ReleaseMutex (input_mutex
);
1577 if (get_ttyp ()->read_retval
< 0) // read error
1579 set_errno (-get_ttyp ()->read_retval
);
1583 if (get_ttyp ()->read_retval
== 0) //EOF
1585 termios_printf ("saw EOF");
1588 if (get_ttyp ()->ti
.c_lflag
& ICANON
|| is_nonblocking ())
1590 if (vmin
&& totalread
>= vmin
)
1593 /* vmin == 0 && vtime == 0:
1594 * we've already read all input, if any, so return immediately
1595 * vmin == 0 && vtime > 0:
1596 * we've waited for input 10*vtime ms in WFSO(input_available_event),
1597 * no matter whether any input arrived, we shouldn't wait any longer,
1598 * so return immediately
1599 * vmin > 0 && vtime == 0:
1600 * here, totalread < vmin, so continue waiting until more data
1602 * vmin > 0 && vtime > 0:
1603 * similar to the previous here, totalread < vmin, and timer
1604 * hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT,
1605 * so "restart timer" and wait until more data arrive
1612 termios_printf ("%d = read(%p, %lu)", totalread
, ptr
, len
);
1613 len
= (size_t) totalread
;
1615 { /* Not tcflush() */
1616 bool saw_eol
= totalread
> 0 && strchr ("\r\n", ptr0
[totalread
-1]);
1617 mask_switch_to_pcon_in (false, saw_eol
|| len
== 0);
1622 fhandler_pty_slave::dup (fhandler_base
*child
, int flags
)
1624 /* This code was added in Oct 2001 for some undisclosed reason.
1625 However, setting the controlling tty on a dup causes rxvt to
1626 hang when the parent does a dup since the controlling pgid changes.
1627 Specifically testing for -2 (ctty has been setsid'ed) works around
1628 this problem. However, it's difficult to see scenarios in which you
1629 have a dup'able fd, no controlling tty, and not having run setsid.
1630 So, we might want to consider getting rid of the set_ctty in tty-like dup
1631 methods entirely at some point */
1632 if (myself
->ctty
!= -2)
1633 myself
->set_ctty (this, flags
);
1634 report_tty_counts (child
, "duped slave", "");
1639 fhandler_pty_master::dup (fhandler_base
*child
, int)
1641 report_tty_counts (child
, "duped master", "");
1646 fhandler_pty_slave::tcgetattr (struct termios
*t
)
1648 reset_switch_to_pcon ();
1649 *t
= get_ttyp ()->ti
;
1651 /* Workaround for rlwrap */
1652 cygheap_fdenum
cfd (false);
1653 while (cfd
.next () >= 0)
1654 if (cfd
->get_major () == DEV_PTYM_MAJOR
1655 && cfd
->get_minor () == get_minor ())
1657 if (get_ttyp ()->pcon_start
)
1658 t
->c_lflag
&= ~(ICANON
| ECHO
);
1659 if (get_ttyp ()->pcon_activated
)
1660 t
->c_iflag
&= ~ICRNL
;
1667 fhandler_pty_slave::tcsetattr (int, const struct termios
*t
)
1669 reset_switch_to_pcon ();
1670 acquire_output_mutex (mutex_timeout
);
1671 get_ttyp ()->ti
= *t
;
1672 release_output_mutex ();
1677 fhandler_pty_slave::tcflush (int queue
)
1681 termios_printf ("tcflush(%d) handle %p", queue
, get_handle ());
1683 reset_switch_to_pcon ();
1685 if (queue
== TCIFLUSH
|| queue
== TCIOFLUSH
)
1687 size_t len
= UINT_MAX
;
1689 ret
= ((int) len
) >= 0 ? 0 : -1;
1691 if (queue
== TCOFLUSH
|| queue
== TCIOFLUSH
)
1693 /* do nothing for now. */
1696 termios_printf ("%d=tcflush(%d)", ret
, queue
);
1701 fhandler_pty_slave::ioctl (unsigned int cmd
, void *arg
)
1703 termios_printf ("ioctl (%x)", cmd
);
1704 reset_switch_to_pcon ();
1705 int res
= fhandler_termios::ioctl (cmd
, arg
);
1709 if (myself
->pgid
&& get_ttyp ()->getpgid () != myself
->pgid
1710 && (unsigned) myself
->ctty
== FHDEV (DEV_PTYS_MAJOR
, get_minor ())
1711 && (get_ttyp ()->ti
.c_lflag
& TOSTOP
))
1713 /* background process */
1714 termios_printf ("bg ioctl pgid %d, tpgid %d, %s", myself
->pgid
,
1715 get_ttyp ()->getpgid (), myctty ());
1727 pid_t pid
= this->tcgetpgrp ();
1732 *((pid_t
*) arg
) = pid
;
1738 retval
= this->tcsetpgrp ((pid_t
) (intptr_t) arg
);
1743 if (!bytes_available (n
))
1750 *(int *) arg
= (int) n
;
1756 return fhandler_base::ioctl (cmd
, arg
);
1759 acquire_output_mutex (mutex_timeout
);
1761 get_ttyp ()->cmd
= cmd
;
1762 get_ttyp ()->ioctl_retval
= 0;
1766 get_ttyp ()->arg
.winsize
= get_ttyp ()->winsize
;
1767 *(struct winsize
*) arg
= get_ttyp ()->arg
.winsize
;
1768 get_ttyp ()->winsize
= get_ttyp ()->arg
.winsize
;
1771 if (get_ttyp ()->winsize
.ws_row
!= ((struct winsize
*) arg
)->ws_row
1772 || get_ttyp ()->winsize
.ws_col
!= ((struct winsize
*) arg
)->ws_col
1773 || get_ttyp ()->winsize
.ws_ypixel
!= ((struct winsize
*) arg
)->ws_ypixel
1774 || get_ttyp ()->winsize
.ws_xpixel
!= ((struct winsize
*) arg
)->ws_xpixel
1777 if (get_ttyp ()->pcon_activated
&& get_ttyp ()->pcon_pid
)
1778 resize_pseudo_console ((struct winsize
*) arg
);
1779 get_ttyp ()->arg
.winsize
= *(struct winsize
*) arg
;
1780 get_ttyp ()->winsize
= *(struct winsize
*) arg
;
1781 get_ttyp ()->kill_pgrp (SIGWINCH
);
1786 release_output_mutex ();
1787 retval
= get_ttyp ()->ioctl_retval
;
1790 set_errno (-retval
);
1795 termios_printf ("%d = ioctl(%x)", retval
, cmd
);
1800 fhandler_pty_slave::fstat (struct stat
*st
)
1802 fhandler_base::fstat (st
);
1804 bool to_close
= false;
1805 if (!input_available_event
)
1808 shared_name (buf
, INPUT_AVAILABLE_EVENT
, get_minor ());
1809 input_available_event
= OpenEvent (READ_CONTROL
, TRUE
, buf
);
1810 if (input_available_event
)
1813 st
->st_mode
= S_IFCHR
;
1814 if (!input_available_event
1815 || get_object_attribute (input_available_event
, &st
->st_uid
, &st
->st_gid
,
1818 /* If we can't access the ACL, or if the tty doesn't actually exist,
1819 then fake uid and gid to strict, system-like values. */
1820 st
->st_mode
= S_IFCHR
| S_IRUSR
| S_IWUSR
;
1825 CloseHandle (input_available_event
);
1830 fhandler_pty_slave::facl (int cmd
, int nentries
, aclent_t
*aclbufp
)
1833 bool to_close
= false;
1834 security_descriptor sd
;
1835 mode_t attr
= S_IFCHR
;
1840 if (!aclsort32 (nentries
, 0, aclbufp
))
1841 set_errno (ENOTSUP
);
1851 if (!input_available_event
)
1854 shared_name (buf
, INPUT_AVAILABLE_EVENT
, get_minor ());
1855 input_available_event
= OpenEvent (READ_CONTROL
, TRUE
, buf
);
1856 if (input_available_event
)
1859 if (!input_available_event
1860 || get_object_sd (input_available_event
, sd
))
1862 res
= get_posix_access (NULL
, &attr
, NULL
, NULL
, aclbufp
, nentries
);
1863 if (aclbufp
&& res
== MIN_ACL_ENTRIES
)
1865 aclbufp
[0].a_perm
= S_IROTH
| S_IWOTH
;
1866 aclbufp
[0].a_id
= 18;
1867 aclbufp
[1].a_id
= 544;
1872 res
= get_posix_access (sd
, &attr
, NULL
, NULL
, aclbufp
, nentries
);
1874 res
= get_posix_access (sd
, &attr
, NULL
, NULL
, NULL
, 0);
1881 CloseHandle (input_available_event
);
1885 /* Helper function for fchmod and fchown, which just opens all handles
1886 and signals success via bool return. */
1888 fhandler_pty_slave::fch_open_handles (bool chown
)
1891 DWORD write_access
= WRITE_DAC
| (chown
? WRITE_OWNER
: 0);
1893 _tc
= cygwin_shared
->tty
[get_minor ()];
1894 shared_name (buf
, INPUT_AVAILABLE_EVENT
, get_minor ());
1895 input_available_event
= OpenEvent (READ_CONTROL
| write_access
,
1897 output_mutex
= get_ttyp ()->open_output_mutex (write_access
);
1898 input_mutex
= get_ttyp ()->open_input_mutex (write_access
);
1899 pcon_mutex
= get_ttyp ()->open_mutex (PCON_MUTEX
, write_access
);
1900 inuse
= get_ttyp ()->open_inuse (write_access
);
1901 if (!input_available_event
|| !output_mutex
|| !input_mutex
|| !inuse
)
1909 /* Helper function for fchmod and fchown, which sets the new security
1910 descriptor on all objects representing the pty. */
1912 fhandler_pty_slave::fch_set_sd (security_descriptor
&sd
, bool chown
)
1914 security_descriptor sd_old
;
1916 get_object_sd (input_available_event
, sd_old
);
1917 if (!set_object_sd (input_available_event
, sd
, chown
)
1918 && !set_object_sd (output_mutex
, sd
, chown
)
1919 && !set_object_sd (input_mutex
, sd
, chown
)
1920 && !set_object_sd (inuse
, sd
, chown
))
1922 set_object_sd (input_available_event
, sd_old
, chown
);
1923 set_object_sd (output_mutex
, sd_old
, chown
);
1924 set_object_sd (input_mutex
, sd_old
, chown
);
1925 set_object_sd (inuse
, sd_old
, chown
);
1929 /* Helper function for fchmod and fchown, which closes all object handles in
1932 fhandler_pty_slave::fch_close_handles ()
1934 close_maybe (input_available_event
);
1935 close_maybe (output_mutex
);
1936 close_maybe (input_mutex
);
1937 close_maybe (inuse
);
1941 fhandler_pty_slave::fchmod (mode_t mode
)
1944 bool to_close
= false;
1945 security_descriptor sd
;
1948 mode_t orig_mode
= S_IFCHR
;
1950 if (!input_available_event
)
1953 if (!fch_open_handles (false))
1956 sd
.malloc (sizeof (SECURITY_DESCRIPTOR
));
1957 RtlCreateSecurityDescriptor (sd
, SECURITY_DESCRIPTOR_REVISION
);
1958 if (!get_object_attribute (input_available_event
, &uid
, &gid
, &orig_mode
)
1959 && !create_object_sd_from_attribute (uid
, gid
, S_IFCHR
| mode
, sd
))
1960 ret
= fch_set_sd (sd
, false);
1963 fch_close_handles ();
1968 fhandler_pty_slave::fchown (uid_t uid
, gid_t gid
)
1971 bool to_close
= false;
1972 security_descriptor sd
;
1975 mode_t mode
= S_IFCHR
;
1977 if (uid
== ILLEGAL_UID
&& gid
== ILLEGAL_GID
)
1979 if (!input_available_event
)
1982 if (!fch_open_handles (true))
1985 sd
.malloc (sizeof (SECURITY_DESCRIPTOR
));
1986 RtlCreateSecurityDescriptor (sd
, SECURITY_DESCRIPTOR_REVISION
);
1987 if (!get_object_attribute (input_available_event
, &o_uid
, &o_gid
, &mode
))
1989 if (uid
== ILLEGAL_UID
)
1991 if (gid
== ILLEGAL_GID
)
1993 if (uid
== o_uid
&& gid
== o_gid
)
1995 else if (!create_object_sd_from_attribute (uid
, gid
, mode
, sd
))
1996 ret
= fch_set_sd (sd
, true);
2000 fch_close_handles ();
2004 /*******************************************************
2007 fhandler_pty_master::fhandler_pty_master (int unit
)
2008 : fhandler_pty_common (), pktmode (0), master_ctl (NULL
),
2009 master_thread (NULL
), from_master_nat (NULL
), to_master_nat (NULL
),
2010 from_slave_nat (NULL
), to_slave_nat (NULL
), echo_r (NULL
), echo_w (NULL
),
2011 dwProcessId (0), to_master (NULL
), from_master (NULL
),
2012 master_fwd_thread (NULL
)
2015 dev ().parse (DEV_PTYM_MAJOR
, unit
);
2016 set_name ("/dev/ptmx");
2020 fhandler_pty_master::open (int flags
, mode_t
)
2025 dwProcessId
= GetCurrentProcessId ();
2030 fhandler_pty_master::open_setup (int flags
)
2032 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
2033 char buf
[sizeof ("opened pty master for ptyNNNNNNNNNNN")];
2034 __small_sprintf (buf
, "opened pty master for pty%d", get_minor ());
2035 report_tty_counts (this, buf
, "");
2036 return fhandler_base::open_setup (flags
);
2040 fhandler_pty_common::lseek (off_t
, int)
2047 fhandler_pty_common::close ()
2049 termios_printf ("pty%d <%p,%p> closing",
2050 get_minor (), get_handle (), get_output_handle ());
2051 if (!ForceCloseHandle (input_mutex
))
2052 termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex
);
2053 if (!ForceCloseHandle (pcon_mutex
))
2054 termios_printf ("CloseHandle (pcon_mutex<%p>), %E", pcon_mutex
);
2055 if (!ForceCloseHandle1 (get_handle (), from_pty
))
2056 termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ());
2057 if (!ForceCloseHandle1 (get_output_handle (), to_pty
))
2058 termios_printf ("CloseHandle (get_output_handle ()<%p>), %E",
2059 get_output_handle ());
2065 fhandler_pty_common::resize_pseudo_console (struct winsize
*ws
)
2068 size
.X
= ws
->ws_col
;
2069 size
.Y
= ws
->ws_row
;
2070 HPCON_INTERNAL hpcon_local
;
2072 OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, get_ttyp ()->pcon_pid
);
2073 DuplicateHandle (pcon_owner
, get_ttyp ()->h_pcon_write_pipe
,
2074 GetCurrentProcess (), &hpcon_local
.hWritePipe
,
2075 0, TRUE
, DUPLICATE_SAME_ACCESS
);
2076 ResizePseudoConsole ((HPCON
) &hpcon_local
, size
);
2077 CloseHandle (pcon_owner
);
2078 CloseHandle (hpcon_local
.hWritePipe
);
2082 fhandler_pty_master::cleanup ()
2084 report_tty_counts (this, "closing master", "");
2086 from_master_nat
= from_master
=
2087 to_master_nat
= to_master
= from_slave_nat
= to_slave_nat
= NULL
;
2088 fhandler_base::cleanup ();
2092 fhandler_pty_master::close ()
2094 OBJECT_BASIC_INFORMATION obi
;
2097 termios_printf ("closing from_master_nat(%p)/from_master(%p)/to_master_nat(%p)/to_master(%p) since we own them(%u)",
2098 from_master_nat
, from_master
,
2099 to_master_nat
, to_master
, dwProcessId
);
2100 if (cygwin_finished_initializing
)
2102 if (master_ctl
&& get_ttyp ()->master_pid
== myself
->pid
)
2105 pipe_request req
= { (DWORD
) -1 };
2109 __small_sprintf (buf
, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
2110 &cygheap
->installation_key
, get_minor ());
2111 acquire_output_mutex (mutex_timeout
);
2114 CallNamedPipe (buf
, &req
, sizeof req
, &repl
, sizeof repl
, &len
,
2116 CloseHandle (master_ctl
);
2117 master_thread
->detach ();
2118 get_ttyp ()->set_master_ctl_closed ();
2121 release_output_mutex ();
2122 get_ttyp ()->stop_fwd_thread
= true;
2123 WriteFile (to_master_nat
, "", 0, NULL
, NULL
);
2124 master_fwd_thread
->detach ();
2128 /* Check if the last master handle has been closed. If so, set
2129 input_available_event to wake up potentially waiting slaves. */
2130 acquire_output_mutex (mutex_timeout
);
2131 status
= NtQueryObject (get_output_handle (), ObjectBasicInformation
,
2132 &obi
, sizeof obi
, NULL
);
2133 fhandler_pty_common::close ();
2134 release_output_mutex ();
2135 if (!ForceCloseHandle (output_mutex
))
2136 termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex
);
2137 if (!NT_SUCCESS (status
))
2138 debug_printf ("NtQueryObject: %y", status
);
2139 else if (obi
.HandleCount
== 1)
2141 termios_printf ("Closing last master of pty%d", get_minor ());
2142 if (get_ttyp ()->getsid () > 0)
2143 kill (get_ttyp ()->getsid (), SIGHUP
);
2144 SetEvent (input_available_event
);
2147 if (!ForceCloseHandle (from_master_nat
))
2148 termios_printf ("error closing from_master_nat %p, %E", from_master_nat
);
2149 if (!ForceCloseHandle (to_master_nat
))
2150 termios_printf ("error closing to_master_nat %p, %E", to_master_nat
);
2151 from_master_nat
= to_master_nat
= NULL
;
2152 if (!ForceCloseHandle (from_slave_nat
))
2153 termios_printf ("error closing from_slave_nat %p, %E", from_slave_nat
);
2154 from_slave_nat
= NULL
;
2155 if (!ForceCloseHandle (to_master
))
2156 termios_printf ("error closing to_master %p, %E", to_master
);
2158 ForceCloseHandle (echo_r
);
2159 ForceCloseHandle (echo_w
);
2160 echo_r
= echo_w
= NULL
;
2162 ForceCloseHandle (to_slave_nat
);
2163 to_slave_nat
= NULL
;
2165 if (have_execed
|| get_ttyp ()->master_pid
!= myself
->pid
)
2166 termios_printf ("not clearing: %d, master_pid %d",
2167 have_execed
, get_ttyp ()->master_pid
);
2168 if (!ForceCloseHandle (input_available_event
))
2169 termios_printf ("CloseHandle (input_available_event<%p>), %E",
2170 input_available_event
);
2172 /* The from_master must be closed last so that the same pty is not
2173 allocated before cleaning up the other corresponding instances. */
2174 if (!ForceCloseHandle (from_master
))
2175 termios_printf ("error closing from_master %p, %E", from_master
);
2182 fhandler_pty_master::write (const void *ptr
, size_t len
)
2185 char *p
= (char *) ptr
;
2186 termios
&ti
= tc ()->ti
;
2188 bg_check_types bg
= bg_check (SIGTTOU
);
2190 return (ssize_t
) bg
;
2192 push_process_state
process_state (PID_TTYOU
);
2194 if (get_ttyp ()->pcon_start
)
2196 /* Pseudo condole support uses "CSI6n" to get cursor position.
2197 If the reply for "CSI6n" is divided into multiple writes,
2198 pseudo console sometimes does not recognize it. Therefore,
2199 put them together into wpbuf and write all at once. */
2200 static const int wpbuf_len
= strlen ("\033[32768;32868R");
2201 static char wpbuf
[wpbuf_len
];
2202 static int ixput
= 0;
2203 static int state
= 0;
2206 WaitForSingleObject (input_mutex
, mutex_timeout
);
2207 for (size_t i
= 0; i
< len
; i
++)
2212 line_edit (wpbuf
, ixput
, ti
, &ret
);
2218 if (ixput
< wpbuf_len
)
2219 wpbuf
[ixput
++] = p
[i
];
2222 if (!get_ttyp ()->req_xfer_input
)
2223 WriteFile (to_slave_nat
, wpbuf
, ixput
, &n
, NULL
);
2225 wpbuf
[ixput
++] = p
[i
];
2229 line_edit (p
+ i
, 1, ti
, &ret
);
2230 if (state
== 1 && p
[i
] == 'R')
2235 if (!get_ttyp ()->req_xfer_input
)
2236 WriteFile (to_slave_nat
, wpbuf
, ixput
, &n
, NULL
);
2239 get_ttyp ()->req_xfer_input
= false;
2240 get_ttyp ()->pcon_start
= false;
2242 ReleaseMutex (input_mutex
);
2244 if (!get_ttyp ()->pcon_start
)
2246 pinfo
pp (get_ttyp ()->pcon_start_pid
);
2247 bool pcon_fg
= (pp
&& get_ttyp ()->getpgid () == pp
->pgid
);
2248 /* GDB may set WINPID rather than cygwin PID to process group
2249 when the debugged process is a non-cygwin process.*/
2250 pcon_fg
|= !pinfo (get_ttyp ()->getpgid ());
2251 if (get_ttyp ()->switch_to_pcon_in
&& pcon_fg
2252 && get_ttyp ()->pcon_input_state_eq (tty::to_cyg
))
2254 /* This accept_input() call is needed in order to transfer input
2255 which is not accepted yet to non-cygwin pipe. */
2256 if (get_readahead_valid ())
2258 WaitForSingleObject (input_mutex
, mutex_timeout
);
2259 fhandler_pty_slave::transfer_input (tty::to_nat
, from_master
,
2261 input_available_event
);
2262 ReleaseMutex (input_mutex
);
2264 get_ttyp ()->pcon_start_pid
= 0;
2270 /* Write terminal input to to_slave_nat pipe instead of output_handle
2271 if current application is native console application. */
2272 WaitForSingleObject (input_mutex
, mutex_timeout
);
2273 if (to_be_read_from_pcon () && get_ttyp ()->pcon_activated
2274 && get_ttyp ()->pcon_input_state
== tty::to_nat
)
2277 char *buf
= (char *) ptr
;
2279 if (get_ttyp ()->term_code_page
!= CP_UTF8
)
2281 static mbstate_t mbp
;
2284 convert_mb_str (CP_UTF8
, buf
, &nlen
,
2285 get_ttyp ()->term_code_page
, (const char *) ptr
, len
,
2289 if ((ti
.c_lflag
& ISIG
) && memchr (buf
, '\003', nlen
))
2291 /* If the process is started with CREATE_NEW_PROCESS_GROUP
2292 flag, Ctrl-C will not be sent to that process. Therefore,
2293 send Ctrl-break event to that process here. */
2295 winpids
pids ((DWORD
) 0);
2296 for (unsigned i
= 0; i
< pids
.npids
; i
++)
2298 _pinfo
*p
= pids
[i
];
2299 if (p
->ctty
== get_ttyp ()->ntty
2300 && p
->pgid
== get_ttyp ()->getpgid ()
2301 && (p
->process_state
& PID_NOTCYGWIN
)
2302 && (p
->process_state
& PID_NEW_PG
))
2304 wpid
= p
->dwProcessId
;
2308 pinfo pinfo_resume
= pinfo (myself
->ppid
);
2311 resume_pid
= pinfo_resume
->dwProcessId
;
2313 resume_pid
= get_console_process_id (myself
->dwProcessId
, false);
2314 if (wpid
&& resume_pid
)
2316 WaitForSingleObject (pcon_mutex
, INFINITE
);
2318 AttachConsole (wpid
);
2319 /* CTRL_C_EVENT does not work for the process started with
2320 CREATE_NEW_PROCESS_GROUP flag, so send CTRL_BREAK_EVENT
2322 GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT
, wpid
);
2324 AttachConsole (resume_pid
);
2325 ReleaseMutex (pcon_mutex
);
2327 if (!(ti
.c_lflag
& NOFLSH
))
2328 get_ttyp ()->discard_input
= true;
2331 WriteFile (to_slave_nat
, buf
, nlen
, &n
, NULL
);
2332 ReleaseMutex (input_mutex
);
2337 /* This input transfer is needed when cygwin-app which is started from
2338 non-cygwin app is terminated if pseudo console is disabled. */
2339 if (to_be_read_from_pcon () && !get_ttyp ()->pcon_activated
2340 && get_ttyp ()->pcon_input_state
== tty::to_cyg
)
2341 fhandler_pty_slave::transfer_input (tty::to_nat
, from_master
,
2342 get_ttyp (), input_available_event
);
2343 ReleaseMutex (input_mutex
);
2345 line_edit_status status
= line_edit (p
, len
, ti
, &ret
);
2346 if (status
> line_edit_signalled
&& status
!= line_edit_pipe_full
)
2352 fhandler_pty_master::read (void *ptr
, size_t& len
)
2354 bg_check_types bg
= bg_check (SIGTTIN
);
2360 push_process_state
process_state (PID_TTYIN
);
2361 len
= (size_t) process_slave_output ((char *) ptr
, len
, pktmode
);
2365 fhandler_pty_master::tcgetattr (struct termios
*t
)
2367 *t
= cygwin_shared
->tty
[get_minor ()]->ti
;
2368 /* Workaround for rlwrap v0.40 or later */
2369 if (get_ttyp ()->pcon_start
)
2370 t
->c_lflag
&= ~(ICANON
| ECHO
);
2371 if (get_ttyp ()->pcon_activated
)
2372 t
->c_iflag
&= ~ICRNL
;
2377 fhandler_pty_master::tcsetattr (int, const struct termios
*t
)
2379 cygwin_shared
->tty
[get_minor ()]->ti
= *t
;
2384 fhandler_pty_master::tcflush (int queue
)
2388 termios_printf ("tcflush(%d) handle %p", queue
, get_handle ());
2390 if (queue
== TCIFLUSH
|| queue
== TCIOFLUSH
)
2391 ret
= process_slave_output (NULL
, OUT_BUFFER_SIZE
, 0);
2392 if (queue
== TCOFLUSH
|| queue
== TCIOFLUSH
)
2394 /* do nothing for now. */
2397 termios_printf ("%d=tcflush(%d)", ret
, queue
);
2402 fhandler_pty_master::ioctl (unsigned int cmd
, void *arg
)
2404 int res
= fhandler_termios::ioctl (cmd
, arg
);
2411 pktmode
= *(int *) arg
;
2414 *(struct winsize
*) arg
= get_ttyp ()->winsize
;
2417 if (get_ttyp ()->winsize
.ws_row
!= ((struct winsize
*) arg
)->ws_row
2418 || get_ttyp ()->winsize
.ws_col
!= ((struct winsize
*) arg
)->ws_col
2419 || get_ttyp ()->winsize
.ws_ypixel
!= ((struct winsize
*) arg
)->ws_ypixel
2420 || get_ttyp ()->winsize
.ws_xpixel
!= ((struct winsize
*) arg
)->ws_xpixel
2423 if (get_ttyp ()->pcon_activated
&& get_ttyp ()->pcon_pid
)
2424 resize_pseudo_console ((struct winsize
*) arg
);
2425 get_ttyp ()->winsize
= *(struct winsize
*) arg
;
2426 get_ttyp ()->kill_pgrp (SIGWINCH
);
2430 *((pid_t
*) arg
) = this->tcgetpgrp ();
2433 return this->tcsetpgrp ((pid_t
) (intptr_t) arg
);
2437 if (!bytes_available (n
))
2442 *(int *) arg
= (int) n
;
2446 return fhandler_base::ioctl (cmd
, arg
);
2452 fhandler_pty_master::ptsname_r (char *buf
, size_t buflen
)
2454 char tmpbuf
[TTY_NAME_MAX
];
2456 __ptsname (tmpbuf
, get_minor ());
2457 if (buflen
<= strlen (tmpbuf
))
2462 strcpy (buf
, tmpbuf
);
2467 fhandler_pty_common::set_close_on_exec (bool val
)
2469 // Cygwin processes will handle this specially on exec.
2470 close_on_exec (val
);
2474 fhandler_pty_slave::setup_locale (void)
2476 extern UINT
__eval_codepage_from_internal_charset ();
2478 if (!get_ttyp ()->term_code_page
)
2480 get_ttyp ()->term_code_page
= __eval_codepage_from_internal_charset ();
2481 SetConsoleCP (get_ttyp ()->term_code_page
);
2482 SetConsoleOutputCP (get_ttyp ()->term_code_page
);
2487 fhandler_pty_slave::fixup_after_fork (HANDLE parent
)
2489 // fork_fixup (parent, inuse, "inuse");
2490 // fhandler_pty_common::fixup_after_fork (parent);
2491 report_tty_counts (this, "inherited", "");
2495 fhandler_pty_slave::fixup_after_exec ()
2497 reset_switch_to_pcon ();
2498 create_invisible_console ();
2500 if (!close_on_exec ())
2501 fixup_after_fork (NULL
); /* No parent handle required. */
2503 /* Hook Console API */
2504 #define DO_HOOK(module, name) \
2507 void *api = hook_api (module, #name, (void *) name##_Hooked); \
2508 name##_Orig = (__typeof__ (name) *) api; \
2509 /*if (api) system_printf (#name " hooked.");*/ \
2511 /* CreateProcess() is hooked for GDB etc. */
2512 DO_HOOK (NULL
, CreateProcessA
);
2513 DO_HOOK (NULL
, CreateProcessW
);
2516 /* This thread function handles the master control pipe. It waits for a
2517 client to connect. Then it checks if the client process has permissions
2518 to access the tty handles. If so, it opens the client process and
2519 duplicates the handles into that process. If that fails, it sends a reply
2520 with at least one handle set to NULL and an error code. Last but not
2521 least, the client is disconnected and the thread waits for the next client.
2523 A special case is when the master side of the tty is about to be closed.
2524 The client side is the fhandler_pty_master::close function and it sends
2525 a PID -1 in that case. A check is performed that the request to leave
2526 really comes from the master process itself.
2528 Since there's always only one pipe instance, there's a chance that clients
2529 have to wait to connect to the master control pipe. Therefore the client
2530 calls to CallNamedPipe should have a big enough timeout value. For now this
2531 is 500ms. Hope that's enough. */
2533 /* The function pty_master_thread() should be static because the instance
2534 is deleted if the master is dup()'ed and the original is closed. In
2535 this case, dup()'ed instance still exists, therefore, master thread
2536 is also still alive even though the instance has been deleted. As a
2537 result, accesing member variables in this function causes access
2541 fhandler_pty_master::pty_master_thread (const master_thread_param_t
*p
)
2544 GENERIC_MAPPING map
= { EVENT_QUERY_STATE
, EVENT_MODIFY_STATE
, 0,
2545 EVENT_QUERY_STATE
| EVENT_MODIFY_STATE
};
2548 security_descriptor sd
;
2554 termios_printf ("Entered");
2555 while (!exit
&& (ConnectNamedPipe (p
->master_ctl
, NULL
)
2556 || GetLastError () == ERROR_PIPE_CONNECTED
))
2558 pipe_reply repl
= { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, 0 };
2560 NTSTATUS allow
= STATUS_ACCESS_DENIED
;
2561 ACCESS_MASK access
= EVENT_MODIFY_STATE
;
2562 HANDLE client
= NULL
;
2564 if (!ReadFile (p
->master_ctl
, &req
, sizeof req
, &len
, NULL
))
2566 termios_printf ("ReadFile, %E");
2569 if (!GetNamedPipeClientProcessId (p
->master_ctl
, &pid
))
2571 if (get_object_sd (p
->input_available_event
, sd
))
2573 termios_printf ("get_object_sd, %E");
2576 cygheap
->user
.deimpersonate ();
2578 if (!ImpersonateNamedPipeClient (p
->master_ctl
))
2580 termios_printf ("ImpersonateNamedPipeClient, %E");
2583 status
= NtOpenThreadToken (GetCurrentThread (), TOKEN_QUERY
, TRUE
,
2585 if (!NT_SUCCESS (status
))
2587 termios_printf ("NtOpenThreadToken, %y", status
);
2588 SetLastError (RtlNtStatusToDosError (status
));
2592 status
= NtAccessCheck (sd
, token
, access
, &map
, &ps
, &len
, &access
,
2595 if (!NT_SUCCESS (status
))
2597 termios_printf ("NtAccessCheck, %y", status
);
2598 SetLastError (RtlNtStatusToDosError (status
));
2601 if (!RevertToSelf ())
2603 termios_printf ("RevertToSelf, %E");
2606 if (req
.pid
== (DWORD
) -1) /* Request to finish thread. */
2608 /* Check if the requesting process is the master process itself. */
2609 if (pid
== GetCurrentProcessId ())
2613 if (NT_SUCCESS (allow
))
2615 client
= OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, pid
);
2618 termios_printf ("OpenProcess, %E");
2621 if (!DuplicateHandle (GetCurrentProcess (), p
->from_master_nat
,
2622 client
, &repl
.from_master_nat
,
2623 0, TRUE
, DUPLICATE_SAME_ACCESS
))
2625 termios_printf ("DuplicateHandle (from_master_nat), %E");
2628 if (!DuplicateHandle (GetCurrentProcess (), p
->from_master
,
2629 client
, &repl
.from_master
,
2630 0, TRUE
, DUPLICATE_SAME_ACCESS
))
2632 termios_printf ("DuplicateHandle (from_master), %E");
2635 if (!DuplicateHandle (GetCurrentProcess (), p
->to_master_nat
,
2636 client
, &repl
.to_master_nat
,
2637 0, TRUE
, DUPLICATE_SAME_ACCESS
))
2639 termios_printf ("DuplicateHandle (to_master_nat), %E");
2642 if (!DuplicateHandle (GetCurrentProcess (), p
->to_master
,
2643 client
, &repl
.to_master
,
2644 0, TRUE
, DUPLICATE_SAME_ACCESS
))
2646 termios_printf ("DuplicateHandle (to_master), %E");
2649 if (!DuplicateHandle (GetCurrentProcess (), p
->to_slave_nat
,
2650 client
, &repl
.to_slave_nat
,
2651 0, TRUE
, DUPLICATE_SAME_ACCESS
))
2653 termios_printf ("DuplicateHandle (to_slave_nat), %E");
2656 if (!DuplicateHandle (GetCurrentProcess (), p
->to_slave
,
2657 client
, &repl
.to_slave
,
2658 0, TRUE
, DUPLICATE_SAME_ACCESS
))
2660 termios_printf ("DuplicateHandle (to_slave), %E");
2665 repl
.error
= GetLastError ();
2667 CloseHandle (client
);
2669 cygheap
->user
.reimpersonate ();
2671 termios_printf ("Reply: from %p, to %p, error %u",
2672 repl
.from_master_nat
, repl
.to_master_nat
, repl
.error
);
2673 if (!WriteFile (p
->master_ctl
, &repl
, sizeof repl
, &len
, NULL
))
2674 termios_printf ("WriteFile, %E");
2675 if (!DisconnectNamedPipe (p
->master_ctl
))
2676 termios_printf ("DisconnectNamedPipe, %E");
2678 termios_printf ("Leaving");
2683 pty_master_thread (VOID
*arg
)
2685 fhandler_pty_master::master_thread_param_t p
;
2686 ((fhandler_pty_master
*) arg
)->get_master_thread_param (&p
);
2687 return fhandler_pty_master::pty_master_thread (&p
);
2690 /* The function pty_master_fwd_thread() should be static because the
2691 instance is deleted if the master is dup()'ed and the original is
2692 closed. In this case, dup()'ed instance still exists, therefore,
2693 master forwarding thread is also still alive even though the instance
2694 has been deleted. As a result, accesing member variables in this
2695 function causes access violation. */
2698 fhandler_pty_master::pty_master_fwd_thread (const master_fwd_thread_param_t
*p
)
2702 char *outbuf
= tp
.c_get ();
2703 char *mbbuf
= tp
.c_get ();
2704 static mbstate_t mbp
;
2706 termios_printf ("Started.");
2709 p
->ttyp
->pcon_last_time
= GetTickCount ();
2710 if (!ReadFile (p
->from_slave_nat
, outbuf
, NT_MAX_PATH
, &rlen
, NULL
))
2712 termios_printf ("ReadFile for forwarding failed, %E");
2715 if (p
->ttyp
->stop_fwd_thread
)
2717 ssize_t wlen
= rlen
;
2719 if (p
->ttyp
->pcon_activated
)
2721 /* Avoid setting window title to "cygwin-console-helper.exe" */
2724 for (DWORD i
=0; i
<rlen
; i
++)
2725 if (outbuf
[i
] == '\033')
2731 else if ((state
== 1 && outbuf
[i
] == ']') ||
2732 (state
== 2 && outbuf
[i
] == '0') ||
2733 (state
== 3 && outbuf
[i
] == ';'))
2738 else if (state
== 4 && outbuf
[i
] == '\a')
2740 const char *helper_str
= "\\bin\\cygwin-console-helper.exe";
2741 if (memmem (&outbuf
[start_at
], i
+ 1 - start_at
,
2742 helper_str
, strlen (helper_str
)))
2744 memmove (&outbuf
[start_at
], &outbuf
[i
+1], rlen
-i
-1);
2745 rlen
= wlen
= start_at
+ rlen
- i
- 1;
2750 else if (outbuf
[i
] == '\a')
2756 /* Remove CSI > Pm m */
2759 for (DWORD i
= 0; i
< rlen
; i
++)
2760 if (outbuf
[i
] == '\033')
2766 else if ((state
== 1 && outbuf
[i
] == '[')
2767 || (state
== 2 && outbuf
[i
] == '>'))
2772 else if (state
== 3 && (isdigit (outbuf
[i
]) || outbuf
[i
] == ';'))
2774 else if (state
== 3 && outbuf
[i
] == 'm')
2776 memmove (&outbuf
[start_at
], &outbuf
[i
+1], rlen
-i
-1);
2777 rlen
= wlen
= start_at
+ rlen
- i
- 1;
2785 /* Remove OSC Ps ; ? BEL/ST */
2786 for (DWORD i
= 0; i
< rlen
; i
++)
2787 if (state
== 0 && outbuf
[i
] == '\033')
2793 else if ((state
== 1 && outbuf
[i
] == ']')
2794 || (state
== 2 && outbuf
[i
] == ';')
2795 || (state
== 3 && outbuf
[i
] == '?')
2796 || (state
== 4 && outbuf
[i
] == '\033'))
2801 else if (state
== 2 && isdigit (outbuf
[i
]))
2803 else if ((state
== 4 && outbuf
[i
] == '\a')
2804 || (state
== 5 && outbuf
[i
] == '\\'))
2806 memmove (&outbuf
[start_at
], &outbuf
[i
+1], rlen
-i
-1);
2807 rlen
= wlen
= start_at
+ rlen
- i
- 1;
2815 if (p
->ttyp
->term_code_page
!= CP_UTF8
)
2817 size_t nlen
= NT_MAX_PATH
;
2818 convert_mb_str (p
->ttyp
->term_code_page
, mbbuf
, &nlen
,
2819 CP_UTF8
, ptr
, wlen
, &mbp
);
2825 /* OPOST processing was already done in pseudo console,
2826 so just write it to to_master. */
2830 if (!WriteFile (p
->to_master
, ptr
, wlen
, &written
, NULL
))
2832 termios_printf ("WriteFile for forwarding failed, %E");
2836 wlen
= (rlen
-= written
);
2842 pinfo pinfo_target
= pinfo (p
->ttyp
->invisible_console_pid
);
2843 DWORD target_pid
= 0;
2845 target_pid
= pinfo_target
->dwProcessId
;
2846 pinfo pinfo_resume
= pinfo (myself
->ppid
);
2849 resume_pid
= pinfo_resume
->dwProcessId
;
2851 resume_pid
= get_console_process_id (myself
->dwProcessId
, false);
2852 if (target_pid
&& resume_pid
)
2854 /* Slave attaches to a different console than master.
2855 Therefore reattach here. */
2856 acquire_attach_mutex (mutex_timeout
);
2858 AttachConsole (target_pid
);
2859 cp_from
= GetConsoleOutputCP ();
2861 AttachConsole (resume_pid
);
2862 release_attach_mutex ();
2865 cp_from
= GetConsoleOutputCP ();
2867 if (p
->ttyp
->term_code_page
!= cp_from
)
2869 size_t nlen
= NT_MAX_PATH
;
2870 convert_mb_str (p
->ttyp
->term_code_page
, mbbuf
, &nlen
,
2871 cp_from
, ptr
, wlen
, &mbp
);
2877 WaitForSingleObject (p
->output_mutex
, mutex_timeout
);
2880 if (!process_opost_output (p
->to_master
, ptr
, wlen
, false,
2883 termios_printf ("WriteFile for forwarding failed, %E");
2887 wlen
= (rlen
-= wlen
);
2889 ReleaseMutex (p
->output_mutex
);
2895 pty_master_fwd_thread (VOID
*arg
)
2897 fhandler_pty_master::master_fwd_thread_param_t p
;
2898 ((fhandler_pty_master
*) arg
)->get_master_fwd_thread_param (&p
);
2899 return fhandler_pty_master::pty_master_fwd_thread (&p
);
2903 is_running_as_service (void)
2905 return check_token_membership (well_known_service_sid
)
2906 || cygheap
->user
.saved_sid () == well_known_system_sid
;
2910 fhandler_pty_master::setup ()
2913 security_descriptor sd
;
2914 SECURITY_ATTRIBUTES sa
= { sizeof (SECURITY_ATTRIBUTES
), NULL
, TRUE
};
2916 /* Find an unallocated pty to use. */
2917 int unit
= cygwin_shared
->tty
.allocate (from_master
, get_output_handle ());
2921 ProtectHandle1 (get_output_handle (), to_pty
);
2923 tty
& t
= *cygwin_shared
->tty
[unit
];
2924 _tc
= (tty_min
*) &t
;
2926 tcinit (true); /* Set termios information. Force initialization. */
2928 const char *errstr
= NULL
;
2929 DWORD pipe_mode
= PIPE_NOWAIT
;
2931 if (!SetNamedPipeHandleState (get_output_handle (), &pipe_mode
, NULL
, NULL
))
2932 termios_printf ("can't set output_handle(%p) to non-blocking mode",
2933 get_output_handle ());
2935 char pipename
[sizeof ("ptyNNNN-from-master-nat")];
2936 __small_sprintf (pipename
, "pty%d-to-master-nat", unit
);
2937 res
= fhandler_pipe::create (&sec_none
, &from_slave_nat
, &to_master_nat
,
2938 fhandler_pty_common::pipesize
, pipename
, 0);
2941 errstr
= "output pipe for non-cygwin apps";
2945 __small_sprintf (pipename
, "pty%d-to-master", unit
);
2946 res
= fhandler_pipe::create (&sec_none
, &get_handle (), &to_master
,
2947 fhandler_pty_common::pipesize
, pipename
, 0);
2950 errstr
= "output pipe";
2954 __small_sprintf (pipename
, "pty%d-from-master-nat", unit
);
2955 /* FILE_FLAG_OVERLAPPED is specified here in order to prevent
2956 PeekNamedPipe() from blocking in transfer_input().
2957 Accordig to the official document, in order to access the handle
2958 opened with FILE_FLAG_OVERLAPPED, it is mandatory to pass the
2959 OVERLAPP structure, but in fact, it seems that the access will
2960 fallback to the blocking access if it is not specified. */
2961 res
= fhandler_pipe::create (&sec_none
, &from_master_nat
, &to_slave_nat
,
2962 fhandler_pty_common::pipesize
, pipename
,
2963 FILE_FLAG_OVERLAPPED
);
2966 errstr
= "input pipe";
2970 ProtectHandle1 (get_handle (), from_pty
);
2972 __small_sprintf (pipename
, "pty%d-echoloop", unit
);
2973 res
= fhandler_pipe::create (&sec_none
, &echo_r
, &echo_w
,
2974 fhandler_pty_common::pipesize
, pipename
, 0);
2977 errstr
= "echo pipe";
2981 /* Create security attribute. Default permissions are 0620. */
2982 sd
.malloc (sizeof (SECURITY_DESCRIPTOR
));
2983 RtlCreateSecurityDescriptor (sd
, SECURITY_DESCRIPTOR_REVISION
);
2984 if (!create_object_sd_from_attribute (myself
->uid
, myself
->gid
,
2985 S_IFCHR
| S_IRUSR
| S_IWUSR
| S_IWGRP
,
2987 sa
.lpSecurityDescriptor
= (PSECURITY_DESCRIPTOR
) sd
;
2989 /* Carefully check that the input_available_event didn't already exist.
2990 This is a measure to make sure that the event security descriptor
2991 isn't occupied by a malicious process. We must make sure that the
2992 event's security descriptor is what we expect it to be. */
2993 if (!(input_available_event
= t
.get_event (errstr
= INPUT_AVAILABLE_EVENT
,
2995 || GetLastError () == ERROR_ALREADY_EXISTS
)
2999 errstr
= shared_name (buf
, OUTPUT_MUTEX
, unit
);
3000 if (!(output_mutex
= CreateMutex (&sa
, FALSE
, buf
)))
3003 errstr
= shared_name (buf
, INPUT_MUTEX
, unit
);
3004 if (!(input_mutex
= CreateMutex (&sa
, FALSE
, buf
)))
3007 errstr
= shared_name (buf
, PCON_MUTEX
, unit
);
3008 if (!(pcon_mutex
= CreateMutex (&sa
, FALSE
, buf
)))
3012 attach_mutex
= CreateMutex (&sa
, FALSE
, NULL
);
3014 /* Create master control pipe which allows the master to duplicate
3015 the pty pipe handles to processes which deserve it. */
3016 __small_sprintf (buf
, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
3017 &cygheap
->installation_key
, unit
);
3018 master_ctl
= CreateNamedPipe (buf
, PIPE_ACCESS_DUPLEX
3019 | FILE_FLAG_FIRST_PIPE_INSTANCE
,
3020 PIPE_WAIT
| PIPE_TYPE_MESSAGE
3021 | PIPE_READMODE_MESSAGE
3022 | PIPE_REJECT_REMOTE_CLIENTS
,
3023 1, 4096, 4096, 0, &sec_all_nih
);
3024 if (master_ctl
== INVALID_HANDLE_VALUE
)
3026 errstr
= "pty master control pipe";
3030 thread_param_copied_event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
3031 master_thread
= new cygthread (::pty_master_thread
, this, "ptym");
3034 errstr
= "pty master control thread";
3037 WaitForSingleObject (thread_param_copied_event
, INFINITE
);
3038 master_fwd_thread
= new cygthread (::pty_master_fwd_thread
, this, "ptymf");
3039 if (!master_fwd_thread
)
3041 errstr
= "pty master forwarding thread";
3044 WaitForSingleObject (thread_param_copied_event
, INFINITE
);
3045 CloseHandle (thread_param_copied_event
);
3047 t
.set_from_master_nat (from_master_nat
);
3048 t
.set_from_master (from_master
);
3049 t
.set_to_master_nat (to_master_nat
);
3050 t
.set_to_master (to_master
);
3051 t
.set_to_slave_nat (to_slave_nat
);
3052 t
.set_to_slave (get_output_handle ());
3053 t
.winsize
.ws_col
= 80;
3054 t
.winsize
.ws_row
= 25;
3055 t
.master_pid
= myself
->pid
;
3057 dev ().parse (DEV_PTYM_MAJOR
, unit
);
3059 t
.master_is_running_as_service
= is_running_as_service ();
3061 termios_printf ("this %p, pty%d opened - from_pty <%p,%p>, to_pty %p",
3062 this, unit
, from_slave_nat
, get_handle (),
3063 get_output_handle ());
3068 close_maybe (from_slave_nat
);
3069 close_maybe (to_slave_nat
);
3070 close_maybe (get_handle ());
3071 close_maybe (get_output_handle ());
3072 close_maybe (input_available_event
);
3073 close_maybe (output_mutex
);
3074 close_maybe (input_mutex
);
3075 close_maybe (from_master_nat
);
3076 close_maybe (to_master_nat
);
3077 close_maybe (to_master
);
3078 close_maybe (echo_r
);
3079 close_maybe (echo_w
);
3080 close_maybe (master_ctl
);
3081 /* The from_master must be closed last so that the same pty is not
3082 allocated before cleaning up the other corresponding instances. */
3083 close_maybe (from_master
);
3084 termios_printf ("pty%d open failed - failed to create %s", unit
, errstr
);
3089 fhandler_pty_master::fixup_after_fork (HANDLE parent
)
3091 DWORD wpid
= GetCurrentProcessId ();
3092 fhandler_pty_master
*arch
= (fhandler_pty_master
*) archetype
;
3093 if (arch
->dwProcessId
!= wpid
)
3095 tty
& t
= *get_ttyp ();
3096 if (myself
->pid
== t
.master_pid
)
3098 t
.set_from_master_nat (arch
->from_master_nat
);
3099 t
.set_from_master (arch
->from_master
);
3100 t
.set_to_master_nat (arch
->to_master_nat
);
3101 t
.set_to_master (arch
->to_master
);
3103 arch
->dwProcessId
= wpid
;
3105 from_master_nat
= arch
->from_master_nat
;
3106 from_master
= arch
->from_master
;
3107 to_master_nat
= arch
->to_master_nat
;
3108 to_master
= arch
->to_master
;
3109 #if 0 /* Not sure if this is necessary. */
3110 from_slave_nat
= arch
->from_slave_nat
;
3111 to_slave_nat
= arch
->to_slave_nat
;
3113 report_tty_counts (this, "inherited master", "");
3117 fhandler_pty_master::fixup_after_exec ()
3119 if (!close_on_exec ())
3120 fixup_after_fork (spawn_info
->parent
);
3122 from_master_nat
= from_master
= to_master_nat
= to_master
=
3123 from_slave_nat
= to_slave_nat
= NULL
;
3127 fhandler_pty_common::process_opost_output (HANDLE h
, const void *ptr
,
3128 ssize_t
& len
, bool is_echo
,
3129 tty
*ttyp
, bool is_nonblocking
)
3131 ssize_t towrite
= len
;
3133 if (ttyp
->ti
.c_lflag
& FLUSHO
)
3134 return res
; /* Discard write data */
3139 if (ttyp
->output_stopped
&& is_nonblocking
)
3150 while (ttyp
->output_stopped
)
3154 if (!(ttyp
->ti
.c_oflag
& OPOST
)) // raw output mode
3156 DWORD n
= MIN (OUT_BUFFER_SIZE
, towrite
);
3157 res
= WriteFile (h
, ptr
, n
, &n
, NULL
);
3160 ptr
= (char *) ptr
+ n
;
3163 else // post-process output
3165 char outbuf
[OUT_BUFFER_SIZE
+ 1];
3166 char *buf
= (char *)ptr
;
3169 while (n
< OUT_BUFFER_SIZE
&& rc
< towrite
)
3174 if ((ttyp
->ti
.c_oflag
& ONOCR
)
3175 && ttyp
->column
== 0)
3180 if (ttyp
->ti
.c_oflag
& OCRNL
)
3187 outbuf
[n
++] = buf
[rc
++];
3192 if (ttyp
->ti
.c_oflag
& ONLCR
)
3197 if (ttyp
->ti
.c_oflag
& ONLRET
)
3199 outbuf
[n
++] = buf
[rc
++];
3202 outbuf
[n
++] = buf
[rc
++];
3207 res
= WriteFile (h
, outbuf
, n
, &n
, NULL
);
3210 ptr
= (char *) ptr
+ rc
;
3218 /* Pseudo console supprot is realized using a tricky technic.
3219 PTY need the pseudo console handles, however, they cannot
3220 be retrieved by normal procedure. Therefore, run a helper
3221 process in a pseudo console and get them from the helper.
3222 Slave process will attach to the pseudo console in the
3223 helper process using AttachConsole(). */
3225 fhandler_pty_slave::setup_pseudoconsole (bool nopcon
)
3227 /* Setting switch_to_pcon_in is necessary even if
3228 pseudo console will not be activated. */
3229 fhandler_base
*fh
= ::cygheap
->fdtab
[0];
3230 if (fh
&& fh
->get_major () == DEV_PTYS_MAJOR
)
3232 fhandler_pty_slave
*ptys
= (fhandler_pty_slave
*) fh
;
3233 ptys
->get_ttyp ()->switch_to_pcon_in
= true;
3234 if (!pcon_pid_alive (ptys
->get_ttyp ()->pcon_pid
))
3235 ptys
->get_ttyp ()->pcon_pid
= myself
->exec_dwProcessId
;
3241 /* If the legacy console mode is enabled, pseudo console seems
3242 not to work as expected. To determine console mode, registry
3243 key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
3244 reg_key
reg (HKEY_CURRENT_USER
, KEY_READ
, L
"Console", NULL
);
3247 if (reg
.get_dword (L
"ForceV2", 1) == 0)
3249 termios_printf ("Pseudo console is disabled "
3250 "because the legacy console mode is enabled.");
3254 HANDLE hpConIn
, hpConOut
;
3255 if (get_ttyp ()->pcon_activated
)
3257 if (GetStdHandle (STD_INPUT_HANDLE
) == get_handle ())
3258 { /* Send CSI6n just for requesting transfer input. */
3260 WaitForSingleObject (input_mutex
, mutex_timeout
);
3261 get_ttyp ()->req_xfer_input
= true;
3262 get_ttyp ()->pcon_start
= true;
3263 get_ttyp ()->pcon_start_pid
= myself
->pid
;
3264 WriteFile (get_output_handle (), "\033[6n", 4, &n
, NULL
);
3265 ReleaseMutex (input_mutex
);
3266 while (get_ttyp ()->pcon_start
)
3269 /* Attach to the pseudo console which already exits. */
3271 OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, get_ttyp ()->pcon_pid
);
3272 if (pcon_owner
== NULL
)
3274 DuplicateHandle (pcon_owner
, get_ttyp ()->h_pcon_in
,
3275 GetCurrentProcess (), &hpConIn
,
3276 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3277 DuplicateHandle (pcon_owner
, get_ttyp ()->h_pcon_out
,
3278 GetCurrentProcess (), &hpConOut
,
3279 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3280 CloseHandle (pcon_owner
);
3282 AttachConsole (get_ttyp ()->pcon_pid
);
3287 PROCESS_INFORMATION pi
;
3288 HANDLE hello
, goodbye
;
3295 (SHORT
) get_ttyp ()->winsize
.ws_col
,
3296 (SHORT
) get_ttyp ()->winsize
.ws_row
3298 const DWORD inherit_cursor
= 1;
3300 SetLastError (ERROR_SUCCESS
);
3301 HRESULT res
= CreatePseudoConsole (size
, get_handle_nat (),
3302 get_output_handle_nat (),
3303 inherit_cursor
, &hpcon
);
3304 if (res
!= S_OK
|| GetLastError () == ERROR_PROC_NOT_FOUND
)
3307 system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
3308 GetLastError (), res
);
3312 SIZE_T bytesRequired
;
3313 InitializeProcThreadAttributeList (NULL
, 2, 0, &bytesRequired
);
3314 ZeroMemory (&si
, sizeof (si
));
3315 si
.StartupInfo
.cb
= sizeof (STARTUPINFOEXW
);
3316 si
.lpAttributeList
= (PPROC_THREAD_ATTRIBUTE_LIST
)
3317 HeapAlloc (GetProcessHeap (), 0, bytesRequired
);
3318 if (si
.lpAttributeList
== NULL
)
3319 goto cleanup_pseudo_console
;
3320 if (!InitializeProcThreadAttributeList (si
.lpAttributeList
,
3321 2, 0, &bytesRequired
))
3323 if (!UpdateProcThreadAttribute (si
.lpAttributeList
,
3325 PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
,
3326 hpcon
, sizeof (hpcon
), NULL
, NULL
))
3330 hello
= CreateEvent (&sec_none
, true, false, NULL
);
3331 goodbye
= CreateEvent (&sec_none
, true, false, NULL
);
3332 CreatePipe (&hr
, &hw
, &sec_none
, 0);
3334 HANDLE handles_to_inherit
[] = {hello
, goodbye
, hw
};
3335 if (!UpdateProcThreadAttribute (si
.lpAttributeList
,
3337 PROC_THREAD_ATTRIBUTE_HANDLE_LIST
,
3339 sizeof (handles_to_inherit
),
3341 goto cleanup_event_and_pipes
;
3343 /* Execute helper process */
3344 WCHAR cmd
[MAX_PATH
];
3345 path_conv
helper ("/bin/cygwin-console-helper.exe");
3346 size_t len
= helper
.get_wide_win32_path_len ();
3347 helper
.get_wide_win32_path (cmd
);
3348 __small_swprintf (cmd
+ len
, L
" %p %p %p", hello
, goodbye
, hw
);
3349 si
.StartupInfo
.dwFlags
= STARTF_USESTDHANDLES
;
3350 si
.StartupInfo
.hStdInput
= NULL
;
3351 si
.StartupInfo
.hStdOutput
= NULL
;
3352 si
.StartupInfo
.hStdError
= NULL
;
3354 get_ttyp ()->pcon_activated
= true;
3355 get_ttyp ()->pcon_start
= true;
3356 get_ttyp ()->pcon_start_pid
= myself
->pid
;
3357 if (!CreateProcessW (NULL
, cmd
, &sec_none
, &sec_none
,
3358 TRUE
, EXTENDED_STARTUPINFO_PRESENT
,
3359 NULL
, NULL
, &si
.StartupInfo
, &pi
))
3360 goto cleanup_event_and_pipes
;
3364 DWORD wait_result
= WaitForSingleObject (hello
, 500);
3365 if (wait_result
== WAIT_OBJECT_0
)
3367 if (wait_result
!= WAIT_TIMEOUT
)
3368 goto cleanup_helper_with_hello
;
3370 if (!GetExitCodeProcess (pi
.hProcess
, &exit_code
))
3371 goto cleanup_helper_with_hello
;
3372 if (exit_code
== STILL_ACTIVE
)
3374 if (exit_code
!= 0 ||
3375 WaitForSingleObject (hello
, 500) != WAIT_OBJECT_0
)
3376 goto cleanup_helper_with_hello
;
3379 CloseHandle (hello
);
3380 CloseHandle (pi
.hThread
);
3382 /* Duplicate pseudo console handles */
3385 if (!ReadFile (hr
, buf
, sizeof (buf
), &rlen
, NULL
))
3386 goto cleanup_helper_process
;
3388 sscanf (buf
, "StdHandles=%p,%p", &hpConIn
, &hpConOut
);
3389 if (!DuplicateHandle (pi
.hProcess
, hpConIn
,
3390 GetCurrentProcess (), &hpConIn
, 0,
3391 TRUE
, DUPLICATE_SAME_ACCESS
))
3392 goto cleanup_helper_process
;
3393 if (!DuplicateHandle (pi
.hProcess
, hpConOut
,
3394 GetCurrentProcess (), &hpConOut
, 0,
3395 TRUE
, DUPLICATE_SAME_ACCESS
))
3396 goto cleanup_pcon_in
;
3400 DeleteProcThreadAttributeList (si
.lpAttributeList
);
3401 HeapFree (GetProcessHeap (), 0, si
.lpAttributeList
);
3403 /* Attach to pseudo console */
3405 AttachConsole (pi
.dwProcessId
);
3407 /* Terminate helper process */
3409 WaitForSingleObject (pi
.hProcess
, INFINITE
);
3410 CloseHandle (goodbye
);
3411 CloseHandle (pi
.hProcess
);
3419 HANDLE orig_input_handle_nat
= get_handle_nat ();
3420 HANDLE orig_output_handle_nat
= get_output_handle_nat ();
3421 cygheap_fdenum
cfd (false);
3422 while (cfd
.next () >= 0)
3423 if (cfd
->get_device () == get_device ())
3425 fhandler_base
*fh
= cfd
;
3426 fhandler_pty_slave
*ptys
= (fhandler_pty_slave
*) fh
;
3427 if (ptys
->get_handle_nat () == orig_input_handle_nat
)
3428 ptys
->set_handle_nat (hpConIn
);
3429 if (ptys
->get_output_handle_nat () == orig_output_handle_nat
)
3430 ptys
->set_output_handle_nat (hpConOut
);
3432 CloseHandle (orig_input_handle_nat
);
3433 CloseHandle (orig_output_handle_nat
);
3437 if (!pcon_pid_alive (get_ttyp ()->pcon_pid
))
3438 get_ttyp ()->pcon_pid
= myself
->exec_dwProcessId
;
3440 if (hpcon
&& pcon_pid_self (get_ttyp ()->pcon_pid
))
3442 HPCON_INTERNAL
*hp
= (HPCON_INTERNAL
*) hpcon
;
3443 get_ttyp ()->h_pcon_write_pipe
= hp
->hWritePipe
;
3444 get_ttyp ()->h_pcon_condrv_reference
= hp
->hConDrvReference
;
3445 get_ttyp ()->h_pcon_conhost_process
= hp
->hConHostProcess
;
3446 DuplicateHandle (GetCurrentProcess (), hpConIn
,
3447 GetCurrentProcess (), &get_ttyp ()->h_pcon_in
,
3448 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3449 DuplicateHandle (GetCurrentProcess (), hpConOut
,
3450 GetCurrentProcess (), &get_ttyp ()->h_pcon_out
,
3451 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3452 /* Discard the pseudo console handler container here.
3453 Reconstruct it temporary when it is needed. */
3454 HeapFree (GetProcessHeap (), 0, hp
);
3457 if (get_ttyp ()->previous_code_page
)
3458 SetConsoleCP (get_ttyp ()->previous_code_page
);
3459 if (get_ttyp ()->previous_output_code_page
)
3460 SetConsoleOutputCP (get_ttyp ()->previous_output_code_page
);
3462 if (get_ttyp ()->getpgid () == myself
->pgid
)
3464 termios
&t
= get_ttyp ()->ti
;
3466 /* Set input mode */
3467 GetConsoleMode (hpConIn
, &mode
);
3468 mode
&= ~(ENABLE_ECHO_INPUT
| ENABLE_LINE_INPUT
| ENABLE_PROCESSED_INPUT
);
3469 if (t
.c_lflag
& ECHO
)
3470 mode
|= ENABLE_ECHO_INPUT
;
3471 if (t
.c_lflag
& ICANON
)
3472 mode
|= ENABLE_LINE_INPUT
;
3473 if (mode
& ENABLE_ECHO_INPUT
&& !(mode
& ENABLE_LINE_INPUT
))
3474 /* This is illegal, so turn off the echo here, and fake it
3475 when we read the characters */
3476 mode
&= ~ENABLE_ECHO_INPUT
;
3477 if (t
.c_lflag
& ISIG
)
3478 mode
|= ENABLE_PROCESSED_INPUT
;
3479 SetConsoleMode (hpConIn
, mode
);
3480 /* Set output mode */
3481 GetConsoleMode (hpConOut
, &mode
);
3482 mode
&= ~DISABLE_NEWLINE_AUTO_RETURN
;
3483 if (!(t
.c_oflag
& OPOST
) || !(t
.c_oflag
& ONLCR
))
3484 mode
|= DISABLE_NEWLINE_AUTO_RETURN
;
3485 SetConsoleMode (hpConOut
, mode
);
3490 cleanup_helper_with_hello
:
3491 CloseHandle (hello
);
3492 CloseHandle (pi
.hThread
);
3493 goto cleanup_helper_process
;
3495 CloseHandle (hpConIn
);
3496 cleanup_helper_process
:
3498 WaitForSingleObject (pi
.hProcess
, INFINITE
);
3499 CloseHandle (pi
.hProcess
);
3500 goto skip_close_hello
;
3501 cleanup_event_and_pipes
:
3502 CloseHandle (hello
);
3504 get_ttyp ()->pcon_start
= false;
3505 get_ttyp ()->pcon_start_pid
= 0;
3506 get_ttyp ()->pcon_activated
= false;
3507 CloseHandle (goodbye
);
3511 HeapFree (GetProcessHeap (), 0, si
.lpAttributeList
);
3512 cleanup_pseudo_console
:
3515 HPCON_INTERNAL
*hp
= (HPCON_INTERNAL
*) hpcon
;
3516 HANDLE tmp
= hp
->hConHostProcess
;
3517 ClosePseudoConsole (hpcon
);
3524 /* The function close_pseudoconsole() should be static so that it can
3525 be called even after the fhandler_pty_slave instance is deleted. */
3527 fhandler_pty_slave::close_pseudoconsole (tty
*ttyp
, DWORD force_switch_to
)
3529 DWORD switch_to
= 0;
3530 if (force_switch_to
)
3532 switch_to
= force_switch_to
;
3533 ttyp
->setpgid (force_switch_to
+ MAX_PID
);
3535 else if (pcon_pid_self (ttyp
->pcon_pid
))
3537 /* Search another process which attaches to the pseudo console */
3538 DWORD current_pid
= myself
->exec_dwProcessId
?: myself
->dwProcessId
;
3539 switch_to
= get_console_process_id (current_pid
, false, true, true);
3541 if (ttyp
->pcon_activated
)
3543 ttyp
->previous_code_page
= GetConsoleCP ();
3544 ttyp
->previous_output_code_page
= GetConsoleOutputCP ();
3545 if (pcon_pid_self (ttyp
->pcon_pid
))
3549 /* Change pseudo console owner to another process */
3551 OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, switch_to
);
3552 HANDLE new_write_pipe
= NULL
;
3553 HANDLE new_condrv_reference
= NULL
;
3554 HANDLE new_conhost_process
= NULL
;
3555 HANDLE new_pcon_in
= NULL
, new_pcon_out
= NULL
;
3556 DuplicateHandle (GetCurrentProcess (),
3557 ttyp
->h_pcon_write_pipe
,
3558 new_owner
, &new_write_pipe
,
3559 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3560 DuplicateHandle (GetCurrentProcess (),
3561 ttyp
->h_pcon_condrv_reference
,
3562 new_owner
, &new_condrv_reference
,
3563 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3564 DuplicateHandle (GetCurrentProcess (),
3565 ttyp
->h_pcon_conhost_process
,
3566 new_owner
, &new_conhost_process
,
3567 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3568 DuplicateHandle (GetCurrentProcess (), ttyp
->h_pcon_in
,
3569 new_owner
, &new_pcon_in
,
3570 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3571 DuplicateHandle (GetCurrentProcess (), ttyp
->h_pcon_out
,
3572 new_owner
, &new_pcon_out
,
3573 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3574 CloseHandle (new_owner
);
3575 CloseHandle (ttyp
->h_pcon_write_pipe
);
3576 CloseHandle (ttyp
->h_pcon_condrv_reference
);
3577 CloseHandle (ttyp
->h_pcon_conhost_process
);
3578 CloseHandle (ttyp
->h_pcon_in
);
3579 CloseHandle (ttyp
->h_pcon_out
);
3580 ttyp
->pcon_pid
= switch_to
;
3581 ttyp
->h_pcon_write_pipe
= new_write_pipe
;
3582 ttyp
->h_pcon_condrv_reference
= new_condrv_reference
;
3583 ttyp
->h_pcon_conhost_process
= new_conhost_process
;
3584 ttyp
->h_pcon_in
= new_pcon_in
;
3585 ttyp
->h_pcon_out
= new_pcon_out
;
3587 pinfo
p (myself
->ppid
);
3590 if (!AttachConsole (p
->dwProcessId
))
3591 AttachConsole (ATTACH_PARENT_PROCESS
);
3594 AttachConsole (ATTACH_PARENT_PROCESS
);
3597 { /* Close pseudo console */
3599 pinfo
p (myself
->ppid
);
3602 if (!AttachConsole (p
->dwProcessId
))
3603 AttachConsole (ATTACH_PARENT_PROCESS
);
3606 AttachConsole (ATTACH_PARENT_PROCESS
);
3607 /* Reconstruct pseudo console handler container here for close */
3608 HPCON_INTERNAL
*hp
=
3609 (HPCON_INTERNAL
*) HeapAlloc (GetProcessHeap (), 0,
3610 sizeof (HPCON_INTERNAL
));
3611 hp
->hWritePipe
= ttyp
->h_pcon_write_pipe
;
3612 hp
->hConDrvReference
= ttyp
->h_pcon_condrv_reference
;
3613 hp
->hConHostProcess
= ttyp
->h_pcon_conhost_process
;
3614 /* HeapFree() will be called in ClosePseudoConsole() */
3615 ClosePseudoConsole ((HPCON
) hp
);
3616 CloseHandle (ttyp
->h_pcon_conhost_process
);
3617 ttyp
->pcon_activated
= false;
3618 ttyp
->switch_to_pcon_in
= false;
3620 ttyp
->pcon_start
= false;
3621 ttyp
->pcon_start_pid
= 0;
3627 pinfo
p (myself
->ppid
);
3630 if (!AttachConsole (p
->dwProcessId
))
3631 AttachConsole (ATTACH_PARENT_PROCESS
);
3634 AttachConsole (ATTACH_PARENT_PROCESS
);
3637 else if (pcon_pid_self (ttyp
->pcon_pid
))
3640 ttyp
->pcon_pid
= switch_to
;
3644 ttyp
->switch_to_pcon_in
= false;
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 (pcon_mutex
, INFINITE
);
3736 WaitForSingleObject (input_mutex
, mutex_timeout
);
3737 /* Set pcon_activated and pcon_start so that the response
3738 will sent to io_handle_nat rather than io_handle. */
3739 get_ttyp ()->pcon_activated
= true;
3740 /* pcon_start will be cleared in master write() when CSI6n is responded. */
3741 get_ttyp ()->pcon_start
= true;
3742 WriteFile (get_output_handle (), "\033[6n", 4, &n
, NULL
);
3743 ReleaseMutex (input_mutex
);
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 ()->pcon_pid
= 0;
3771 ReleaseMutex (pcon_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 (pcon_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. */
3800 fhandler_console::need_invisible (true);
3801 get_ttyp ()->need_invisible_console
= false;
3802 get_ttyp ()->invisible_console_pid
= myself
->pid
;
3804 if (get_ttyp ()->invisible_console_pid
3805 && !pinfo (get_ttyp ()->invisible_console_pid
))
3806 /* If primary slave process does not exist anymore,
3807 this process becomes the primary. */
3808 get_ttyp ()->invisible_console_pid
= myself
->pid
;
3812 fhandler_pty_master::get_master_thread_param (master_thread_param_t
*p
)
3814 p
->from_master_nat
= from_master_nat
;
3815 p
->from_master
= from_master
;
3816 p
->to_master_nat
= to_master_nat
;
3817 p
->to_master
= to_master
;
3818 p
->to_slave_nat
= to_slave_nat
;
3819 p
->to_slave
= get_output_handle ();
3820 p
->master_ctl
= master_ctl
;
3821 p
->input_available_event
= input_available_event
;
3822 SetEvent (thread_param_copied_event
);
3826 fhandler_pty_master::get_master_fwd_thread_param (master_fwd_thread_param_t
*p
)
3828 p
->to_master
= to_master
;
3829 p
->from_slave_nat
= from_slave_nat
;
3830 p
->output_mutex
= output_mutex
;
3831 p
->ttyp
= get_ttyp ();
3832 SetEvent (thread_param_copied_event
);
3835 #define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
3836 #define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
3838 fhandler_pty_slave::transfer_input (tty::xfer_dir dir
, HANDLE from
, tty
*ttyp
,
3839 HANDLE input_available_event
)
3842 if (dir
== tty::to_nat
)
3843 to
= ttyp
->to_slave_nat ();
3845 to
= ttyp
->to_slave ();
3847 pinfo
p (ttyp
->master_pid
);
3848 HANDLE pty_owner
= OpenProcess (PROCESS_DUP_HANDLE
, FALSE
, p
->dwProcessId
);
3851 DuplicateHandle (pty_owner
, to
, GetCurrentProcess (), &to
,
3852 0, TRUE
, DUPLICATE_SAME_ACCESS
);
3853 CloseHandle (pty_owner
);
3857 char pipe
[MAX_PATH
];
3858 __small_sprintf (pipe
,
3859 "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl",
3860 &cygheap
->installation_key
, ttyp
->get_minor ());
3861 pipe_request req
= { GetCurrentProcessId () };
3864 if (!CallNamedPipe (pipe
, &req
, sizeof req
,
3865 &repl
, sizeof repl
, &len
, 500))
3866 return; /* What can we do? */
3867 if (dir
== tty::to_nat
)
3868 to
= repl
.to_slave_nat
;
3873 UINT cp_from
= 0, cp_to
= 0;
3875 if (dir
== tty::to_nat
)
3877 cp_from
= ttyp
->term_code_page
;
3878 if (ttyp
->pcon_activated
)
3881 cp_to
= GetConsoleCP ();
3885 cp_from
= GetConsoleCP ();
3886 cp_to
= ttyp
->term_code_page
;
3890 char *buf
= tp
.c_get ();
3892 bool transfered
= false;
3894 if (dir
== tty::to_cyg
&& ttyp
->pcon_activated
)
3895 { /* from handle is console handle */
3896 INPUT_RECORD r
[INREC_SIZE
];
3898 while (PeekConsoleInputA (from
, r
, INREC_SIZE
, &n
) && n
)
3900 ReadConsoleInputA (from
, r
, n
, &n
);
3901 if (ttyp
->discard_input
)
3905 for (DWORD i
= 0; i
< n
; i
++)
3906 if (r
[i
].EventType
== KEY_EVENT
&& r
[i
].Event
.KeyEvent
.bKeyDown
)
3908 DWORD ctrl_key_state
= r
[i
].Event
.KeyEvent
.dwControlKeyState
;
3909 if (r
[i
].Event
.KeyEvent
.uChar
.AsciiChar
)
3911 if ((ctrl_key_state
& ALT_PRESSED
)
3912 && r
[i
].Event
.KeyEvent
.uChar
.AsciiChar
<= 0x7f)
3913 buf
[len
++] = '\033'; /* Meta */
3914 buf
[len
++] = r
[i
].Event
.KeyEvent
.uChar
.AsciiChar
;
3916 /* Allow Ctrl-Space to emit ^@ */
3917 else if (r
[i
].Event
.KeyEvent
.wVirtualKeyCode
== '2'
3918 && (ctrl_key_state
& CTRL_PRESSED
)
3919 && !(ctrl_key_state
& ALT_PRESSED
))
3922 { /* arrow/function keys */
3923 /* FIXME: The current code generates cygwin terminal
3924 sequence rather than xterm sequence. */
3927 fhandler_console::get_nonascii_key (r
[i
], tmp
);
3930 strcpy (buf
+ len
, add
);
3931 len
+= strlen (add
);
3935 if (cp_to
!= cp_from
)
3937 static mbstate_t mbp
;
3938 char *mbbuf
= tp
.c_get ();
3939 size_t nlen
= NT_MAX_PATH
;
3940 convert_mb_str (cp_to
, mbbuf
, &nlen
, cp_from
, buf
, len
, &mbp
);
3944 /* Call WriteFile() line by line */
3947 while ((p1
= (char *) memchr (p0
, '\r', len
- (p0
- ptr
))))
3951 if (n
&& WriteFile (to
, p0
, n
, &n
, NULL
) && n
)
3955 n
= len
- (p0
- ptr
);
3956 if (n
&& WriteFile (to
, p0
, n
, &n
, NULL
) && n
)
3962 DWORD bytes_in_pipe
;
3963 while (::bytes_available (bytes_in_pipe
, from
) && bytes_in_pipe
)
3965 DWORD n
= MIN (bytes_in_pipe
, NT_MAX_PATH
);
3966 ReadFile (from
, buf
, n
, &n
, NULL
);
3967 if (ttyp
->discard_input
)
3970 if (dir
== tty::to_nat
)
3973 if (ttyp
->pcon_activated
)
3974 while ((p
= (char *) memchr (p
, '\n', n
- (p
- buf
))))
3977 while ((p
= (char *) memchr (p
, '\r', n
- (p
- buf
))))
3980 if (cp_to
!= cp_from
)
3982 static mbstate_t mbp
;
3983 char *mbbuf
= tp
.c_get ();
3984 size_t nlen
= NT_MAX_PATH
;
3985 convert_mb_str (cp_to
, mbbuf
, &nlen
, cp_from
, buf
, n
, &mbp
);
3989 if (n
&& WriteFile (to
, ptr
, n
, &n
, NULL
) && n
)
3994 if (dir
== tty::to_nat
)
3995 ResetEvent (input_available_event
);
3996 else if (transfered
)
3997 SetEvent (input_available_event
);
3998 ttyp
->pcon_input_state
= dir
;
3999 ttyp
->discard_input
= false;