]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* fhandler_tty.cc |
2 | ||
ce006ffa | 3 | Copyright 1997, 1998, 2000, 2001, 2002 Red Hat, Inc. |
1fd5e000 CF |
4 | |
5 | This file is part of Cygwin. | |
6 | ||
7 | This software is a copyrighted work licensed under the terms of the | |
8 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
9 | details. */ | |
10 | ||
4c8d72de | 11 | #include "winsup.h" |
1fd5e000 | 12 | #include <stdio.h> |
1fd5e000 CF |
13 | #include <unistd.h> |
14 | #include <stdlib.h> | |
15 | #include <errno.h> | |
1fd5e000 CF |
16 | #include <ctype.h> |
17 | #include <limits.h> | |
bccd5e0d | 18 | #include "cygerrno.h" |
6b91b8d5 | 19 | #include "security.h" |
bccd5e0d | 20 | #include "fhandler.h" |
47063f00 | 21 | #include "path.h" |
e2ebe117 | 22 | #include "dtable.h" |
bccd5e0d | 23 | #include "sigproc.h" |
84cf3d22 | 24 | #include "pinfo.h" |
b0e82b74 | 25 | #include "cygheap.h" |
29ac7f89 | 26 | #include "shared_info.h" |
f449bfef | 27 | #include "cygwin/cygserver.h" |
b6bd7037 | 28 | #include "cygthread.h" |
1fd5e000 CF |
29 | |
30 | /* Tty master stuff */ | |
31 | ||
32 | fhandler_tty_master NO_COPY *tty_master; | |
33 | ||
34 | static DWORD WINAPI process_input (void *); // Input queue thread | |
35 | static DWORD WINAPI process_output (void *); // Output queue thread | |
36 | static DWORD WINAPI process_ioctl (void *); // Ioctl requests thread | |
37 | ||
711ded6d | 38 | fhandler_tty_master::fhandler_tty_master (int unit) |
6b2a9a2f | 39 | : fhandler_pty_master (FH_TTYM, unit), console (NULL), output_thread (NULL) |
1fd5e000 | 40 | { |
1fd5e000 CF |
41 | } |
42 | ||
43 | int | |
44 | fhandler_tty_master::init (int ntty) | |
45 | { | |
1fd5e000 CF |
46 | termios_printf ("Creating master for tty%d", ntty); |
47 | ||
48 | if (init_console ()) | |
49 | { | |
50 | termios_printf ("can't create fhandler"); | |
51 | return -1; | |
52 | } | |
53 | ||
54 | termios ti; | |
55 | memset (&ti, 0, sizeof (ti)); | |
56 | console->tcsetattr (0, &ti); | |
57 | ||
58 | ttynum = ntty; | |
59 | ||
60 | cygwin_shared->tty[ttynum]->common_init (this); | |
61 | ||
2496a363 | 62 | inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE); |
78ace8a7 | 63 | |
b6bd7037 CF |
64 | cygthread *h; |
65 | h = new cygthread (process_input, NULL, "ttyin"); | |
66 | SetThreadPriority (*h, THREAD_PRIORITY_HIGHEST); | |
1fd5e000 | 67 | |
b6bd7037 CF |
68 | h = new cygthread (process_ioctl, NULL, "ttyioctl"); |
69 | SetThreadPriority (*h, THREAD_PRIORITY_HIGHEST); | |
1fd5e000 | 70 | |
1524ae42 | 71 | output_thread = new cygthread (process_output, cygself, "ttyout"); |
6b2a9a2f | 72 | SetThreadPriority (*output_thread, THREAD_PRIORITY_HIGHEST); |
1fd5e000 CF |
73 | |
74 | return 0; | |
75 | } | |
76 | ||
77 | #ifdef DEBUGGING | |
78 | static class mutex_stack | |
79 | { | |
80 | public: | |
81 | const char *fn; | |
82 | int ln; | |
83 | const char *tname; | |
84 | } ostack[100]; | |
85 | ||
08b78edf | 86 | static int osi; |
1fd5e000 CF |
87 | #endif /*DEBUGGING*/ |
88 | ||
89 | DWORD | |
90 | fhandler_tty_common::__acquire_output_mutex (const char *fn, int ln, | |
91 | DWORD ms) | |
92 | { | |
5abc9b83 | 93 | if (strace.active) |
20d7f758 | 94 | strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: waiting %d ms", ln, ms); |
1fd5e000 CF |
95 | DWORD res = WaitForSingleObject (output_mutex, ms); |
96 | if (res == WAIT_OBJECT_0) | |
97 | { | |
af1dc7cc CF |
98 | #ifndef DEBUGGING |
99 | if (strace.active) | |
20d7f758 | 100 | strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: acquired", ln, res); |
af1dc7cc | 101 | #else |
1fd5e000 CF |
102 | ostack[osi].fn = fn; |
103 | ostack[osi].ln = ln; | |
b6bd7037 | 104 | ostack[osi].tname = cygthread::name (); |
1fd5e000 CF |
105 | termios_printf ("acquired for %s:%d, osi %d", fn, ln, osi); |
106 | osi++; | |
107 | #endif | |
108 | } | |
1fd5e000 CF |
109 | return res; |
110 | } | |
111 | ||
112 | void | |
113 | fhandler_tty_common::__release_output_mutex (const char *fn, int ln) | |
114 | { | |
115 | if (ReleaseMutex (output_mutex)) | |
116 | { | |
af1dc7cc CF |
117 | #ifndef DEBUGGING |
118 | if (strace.active) | |
20d7f758 | 119 | strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex released", ln); |
af1dc7cc | 120 | #else |
1fd5e000 CF |
121 | if (osi > 0) |
122 | osi--; | |
123 | termios_printf ("released at %s:%d, osi %d", fn, ln, osi); | |
2116a175 | 124 | termios_printf (" for %s:%d (%s)", ostack[osi].fn, ostack[osi].ln, ostack[osi].tname); |
1fd5e000 CF |
125 | ostack[osi].ln = -ln; |
126 | #endif | |
127 | } | |
1fd5e000 CF |
128 | } |
129 | ||
1fd5e000 CF |
130 | /* Process tty input. */ |
131 | ||
132 | void | |
133 | fhandler_pty_master::doecho (const void *str, DWORD len) | |
134 | { | |
135 | acquire_output_mutex (INFINITE); | |
774ea162 CF |
136 | if (!WriteFile (get_ttyp ()->to_master, str, len, &len, NULL)) |
137 | termios_printf ("Write to %p failed, %E", get_ttyp ()->to_master); | |
1fd5e000 CF |
138 | // WaitForSingleObject (output_done_event, INFINITE); |
139 | release_output_mutex (); | |
140 | } | |
141 | ||
142 | int | |
143 | fhandler_pty_master::accept_input () | |
144 | { | |
a069f560 | 145 | DWORD bytes_left, written; |
1fd5e000 | 146 | DWORD n; |
306c4b67 | 147 | DWORD rc; |
a069f560 | 148 | char* p; |
306c4b67 ED |
149 | |
150 | rc = WaitForSingleObject (input_mutex, INFINITE); | |
1fd5e000 | 151 | |
a069f560 ED |
152 | bytes_left = n = eat_readahead (-1); |
153 | get_ttyp ()->read_retval = 0; | |
154 | p = rabuf; | |
1fd5e000 | 155 | |
2116a175 | 156 | if (n != 0) |
1fd5e000 | 157 | { |
a069f560 ED |
158 | while (bytes_left > 0) |
159 | { | |
160 | termios_printf ("about to write %d chars to slave", bytes_left); | |
161 | rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL); | |
162 | if (!rc) | |
163 | { | |
164 | debug_printf ("error writing to pipe %E"); | |
165 | break; | |
166 | } | |
167 | get_ttyp ()->read_retval += written; | |
168 | p += written; | |
169 | bytes_left -= written; | |
170 | if (bytes_left > 0) | |
171 | { | |
172 | debug_printf ("to_slave pipe is full"); | |
173 | SetEvent (input_available_event); | |
174 | ReleaseMutex (input_mutex); | |
175 | Sleep (10); | |
176 | rc = WaitForSingleObject (input_mutex, INFINITE); | |
177 | } | |
178 | } | |
1fd5e000 | 179 | } |
306c4b67 ED |
180 | else |
181 | termios_printf ("sending EOF to slave"); | |
182 | SetEvent (input_available_event); | |
183 | ReleaseMutex (input_mutex); | |
1fd5e000 CF |
184 | return get_ttyp ()->read_retval; |
185 | } | |
186 | ||
187 | static DWORD WINAPI | |
9cec3d45 | 188 | process_input (void *) |
1fd5e000 CF |
189 | { |
190 | char rawbuf[INP_BUFFER_SIZE]; | |
191 | ||
192 | while (1) | |
193 | { | |
194 | int nraw = tty_master->console->read ((void *) rawbuf, | |
195 | (size_t) INP_BUFFER_SIZE); | |
95a8465b | 196 | (void) tty_master->line_edit (rawbuf, nraw); |
1fd5e000 CF |
197 | } |
198 | } | |
199 | ||
35f879a6 | 200 | bool |
1fd5e000 CF |
201 | fhandler_pty_master::hit_eof () |
202 | { | |
203 | if (get_ttyp ()->was_opened && !get_ttyp ()->slave_alive ()) | |
204 | { | |
205 | /* We have the only remaining open handle to this pty, and | |
206 | the slave pty has been opened at least once. We treat | |
207 | this as EOF. */ | |
208 | termios_printf ("all other handles closed"); | |
209 | return 1; | |
210 | } | |
211 | return 0; | |
212 | } | |
213 | ||
214 | /* Process tty output requests */ | |
215 | ||
216 | int | |
3f0b4935 | 217 | fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on) |
1fd5e000 CF |
218 | { |
219 | size_t rlen; | |
3f0b4935 | 220 | char outbuf[OUT_BUFFER_SIZE + 1]; |
1fd5e000 CF |
221 | DWORD n; |
222 | int column = 0; | |
774ea162 | 223 | int rc = 0; |
1fd5e000 CF |
224 | |
225 | if (len == 0) | |
774ea162 | 226 | goto out; |
1fd5e000 | 227 | |
3f0b4935 | 228 | if (need_nl) |
1fd5e000 | 229 | { |
3f0b4935 CF |
230 | /* We need to return a left over \n character, resulting from |
231 | \r\n conversion. Note that we already checked for FLUSHO and | |
b98ebf54 | 232 | output_stopped at the time that we read the character, so we |
3f0b4935 CF |
233 | don't check again here. */ |
234 | buf[0] = '\n'; | |
235 | need_nl = 0; | |
14323f6a | 236 | rc = 1; |
3f0b4935 CF |
237 | goto out; |
238 | } | |
1fd5e000 | 239 | |
3f0b4935 CF |
240 | |
241 | for (;;) | |
242 | { | |
774ea162 CF |
243 | /* Set RLEN to the number of bytes to read from the pipe. */ |
244 | rlen = len; | |
245 | if (get_ttyp ()->ti.c_oflag & OPOST && get_ttyp ()->ti.c_oflag & ONLCR) | |
246 | { | |
247 | /* We are going to expand \n to \r\n, so don't read more than | |
248 | half of the number of bytes requested. */ | |
249 | rlen /= 2; | |
250 | if (rlen == 0) | |
251 | rlen = 1; | |
252 | } | |
253 | if (rlen > sizeof outbuf) | |
254 | rlen = sizeof outbuf; | |
1fd5e000 | 255 | |
774ea162 | 256 | HANDLE handle = get_io_handle (); |
1fd5e000 | 257 | |
3f0b4935 CF |
258 | n = 0; // get_readahead_into_buffer (outbuf, len); |
259 | if (!n) | |
1fd5e000 | 260 | { |
3f0b4935 CF |
261 | /* Doing a busy wait like this is quite inefficient, but nothing |
262 | else seems to work completely. Windows should provide some sort | |
263 | of overlapped I/O for pipes, or something, but it doesn't. */ | |
264 | while (1) | |
265 | { | |
266 | if (!PeekNamedPipe (handle, NULL, 0, NULL, &n, NULL)) | |
267 | goto err; | |
268 | if (n > 0) | |
269 | break; | |
270 | if (hit_eof ()) | |
271 | goto out; | |
5fd12fb0 | 272 | if (n == 0 && is_nonblocking ()) |
3f0b4935 CF |
273 | { |
274 | set_errno (EAGAIN); | |
275 | rc = -1; | |
276 | break; | |
277 | } | |
278 | ||
279 | Sleep (10); | |
280 | } | |
281 | ||
282 | if (ReadFile (handle, outbuf, rlen, &n, NULL) == FALSE) | |
774ea162 | 283 | goto err; |
1fd5e000 | 284 | } |
1fd5e000 | 285 | |
3f0b4935 | 286 | termios_printf ("bytes read %u", n); |
29ac7f89 CF |
287 | get_ttyp ()->write_error = 0; |
288 | if (output_done_event != NULL) | |
289 | SetEvent (output_done_event); | |
1fd5e000 | 290 | |
774ea162 | 291 | if (get_ttyp ()->ti.c_lflag & FLUSHO) |
29ac7f89 | 292 | continue; |
1fd5e000 | 293 | |
3f0b4935 CF |
294 | char *optr; |
295 | optr = buf; | |
296 | if (pktmode_on) | |
297 | *optr++ = TIOCPKT_DATA; | |
298 | ||
774ea162 | 299 | if (!(get_ttyp ()->ti.c_oflag & OPOST)) // post-process output |
1fd5e000 | 300 | { |
3f0b4935 CF |
301 | memcpy (optr, outbuf, n); |
302 | optr += n; | |
774ea162 CF |
303 | } |
304 | else // raw output mode | |
305 | { | |
3f0b4935 | 306 | char *iptr = outbuf; |
774ea162 CF |
307 | |
308 | while (n--) | |
1fd5e000 | 309 | { |
774ea162 | 310 | switch (*iptr) |
1fd5e000 | 311 | { |
774ea162 CF |
312 | case '\r': |
313 | if ((get_ttyp ()->ti.c_oflag & ONOCR) && column == 0) | |
314 | { | |
315 | iptr++; | |
316 | continue; | |
317 | } | |
318 | if (get_ttyp ()->ti.c_oflag & OCRNL) | |
319 | *iptr = '\n'; | |
320 | else | |
321 | column = 0; | |
322 | break; | |
323 | case '\n': | |
324 | if (get_ttyp ()->ti.c_oflag & ONLCR) | |
325 | { | |
326 | *optr++ = '\r'; | |
327 | column = 0; | |
328 | } | |
329 | if (get_ttyp ()->ti.c_oflag & ONLRET) | |
330 | column = 0; | |
331 | break; | |
332 | default: | |
333 | column++; | |
334 | break; | |
1fd5e000 | 335 | } |
774ea162 CF |
336 | |
337 | /* Don't store data past the end of the user's buffer. This | |
338 | can happen if the user requests a read of 1 byte when | |
339 | doing \r\n expansion. */ | |
340 | if (optr - buf >= (int) len) | |
1fd5e000 | 341 | { |
774ea162 CF |
342 | if (*iptr != '\n' || n != 0) |
343 | system_printf ("internal error: %d unexpected characters", n); | |
3f0b4935 | 344 | need_nl = 1; |
774ea162 | 345 | break; |
1fd5e000 | 346 | } |
1fd5e000 | 347 | |
774ea162 | 348 | *optr++ = *iptr++; |
1fd5e000 | 349 | } |
774ea162 | 350 | } |
3f0b4935 | 351 | rc = optr - buf; |
774ea162 | 352 | break; |
1fd5e000 | 353 | |
774ea162 CF |
354 | err: |
355 | if (GetLastError () == ERROR_BROKEN_PIPE) | |
356 | rc = 0; | |
357 | else | |
358 | { | |
359 | __seterrno (); | |
360 | rc = -1; | |
1fd5e000 | 361 | } |
774ea162 | 362 | break; |
1fd5e000 | 363 | } |
774ea162 CF |
364 | |
365 | out: | |
366 | termios_printf ("returning %d", rc); | |
367 | return rc; | |
1fd5e000 CF |
368 | } |
369 | ||
370 | static DWORD WINAPI | |
1524ae42 | 371 | process_output (void *self) |
1fd5e000 CF |
372 | { |
373 | char buf[OUT_BUFFER_SIZE*2]; | |
1fd5e000 | 374 | |
3f0b4935 | 375 | for (;;) |
1fd5e000 | 376 | { |
3f0b4935 | 377 | int n = tty_master->process_slave_output (buf, OUT_BUFFER_SIZE, 0); |
6b2a9a2f | 378 | if (n <= 0) |
1fd5e000 | 379 | { |
6b2a9a2f CF |
380 | if (n < 0) |
381 | termios_printf ("ReadFile %E"); | |
1524ae42 | 382 | cygthread *t = (cygthread *) self; |
6b2a9a2f CF |
383 | tty_master->output_thread = NULL; |
384 | t->exit_thread (); | |
1fd5e000 CF |
385 | } |
386 | n = tty_master->console->write ((void *) buf, (size_t) n); | |
29ac7f89 | 387 | tty_master->get_ttyp ()->write_error = n == -1 ? get_errno () : 0; |
1fd5e000 CF |
388 | } |
389 | } | |
390 | ||
391 | ||
392 | /* Process tty ioctl requests */ | |
393 | ||
394 | static DWORD WINAPI | |
9cec3d45 | 395 | process_ioctl (void *) |
1fd5e000 CF |
396 | { |
397 | while (1) | |
398 | { | |
399 | WaitForSingleObject (tty_master->ioctl_request_event, INFINITE); | |
400 | termios_printf ("ioctl() request"); | |
401 | tty_master->get_ttyp ()->ioctl_retval = | |
402 | tty_master->console->ioctl (tty_master->get_ttyp ()->cmd, | |
403 | (void *) &tty_master->get_ttyp ()->arg); | |
404 | SetEvent (tty_master->ioctl_done_event); | |
405 | } | |
406 | } | |
407 | ||
408 | /**********************************************************************/ | |
409 | /* Tty slave stuff */ | |
410 | ||
0476bae5 CF |
411 | fhandler_tty_slave::fhandler_tty_slave (int num) |
412 | : fhandler_tty_common (FH_TTYS, num) | |
1fd5e000 | 413 | { |
7a1174dc | 414 | set_r_no_interrupt (1); |
1fd5e000 CF |
415 | } |
416 | ||
0476bae5 CF |
417 | fhandler_tty_slave::fhandler_tty_slave () |
418 | : fhandler_tty_common (FH_TTYS, 0) | |
1fd5e000 | 419 | { |
af598a3b | 420 | set_r_no_interrupt (1); |
1fd5e000 CF |
421 | } |
422 | ||
f3ea62a8 CF |
423 | /* FIXME: This function needs to close handles when it has |
424 | a failing condition. */ | |
1fd5e000 | 425 | int |
8af0f81d | 426 | fhandler_tty_slave::open (path_conv *, int flags, mode_t) |
1fd5e000 CF |
427 | { |
428 | tcinit (cygwin_shared->tty[ttynum]); | |
429 | ||
430 | attach_tty (ttynum); | |
b98ebf54 | 431 | tc->set_ctty (ttynum, flags); |
1fd5e000 | 432 | |
1bc9effd | 433 | set_flags ((flags & ~O_TEXT) | O_BINARY); |
1fd5e000 CF |
434 | /* Create synchronisation events */ |
435 | char buf[40]; | |
436 | ||
437 | /* output_done_event may or may not exist. It will exist if the tty | |
438 | was opened by fhandler_tty_master::init, normally called at | |
439 | startup if use_tty is non-zero. It will not exist if this is a | |
440 | pty opened by fhandler_pty_master::open. In the former case, tty | |
441 | output is handled by a separate thread which controls output. */ | |
442 | __small_sprintf (buf, OUTPUT_DONE_EVENT, ttynum); | |
443 | output_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf); | |
444 | ||
e62ac9e8 | 445 | if (!(output_mutex = get_ttyp ()->open_output_mutex ())) |
1fd5e000 CF |
446 | { |
447 | termios_printf ("open output mutex failed, %E"); | |
448 | __seterrno (); | |
449 | return 0; | |
450 | } | |
e62ac9e8 | 451 | if (!(input_mutex = get_ttyp ()->open_input_mutex ())) |
306c4b67 ED |
452 | { |
453 | termios_printf ("open input mutex failed, %E"); | |
454 | __seterrno (); | |
455 | return 0; | |
456 | } | |
457 | __small_sprintf (buf, INPUT_AVAILABLE_EVENT, ttynum); | |
458 | if (!(input_available_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf))) | |
459 | { | |
460 | termios_printf ("open input event failed, %E"); | |
461 | __seterrno (); | |
462 | return 0; | |
463 | } | |
1fd5e000 CF |
464 | |
465 | /* The ioctl events may or may not exist. See output_done_event, | |
466 | above. */ | |
467 | __small_sprintf (buf, IOCTL_REQUEST_EVENT, ttynum); | |
468 | ioctl_request_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf); | |
469 | __small_sprintf (buf, IOCTL_DONE_EVENT, ttynum); | |
470 | ioctl_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf); | |
471 | ||
472 | /* FIXME: Needs a method to eliminate tty races */ | |
473 | { | |
474 | acquire_output_mutex (500); | |
2496a363 | 475 | inuse = get_ttyp ()->create_inuse (TTY_SLAVE_ALIVE); |
1fd5e000 CF |
476 | get_ttyp ()->was_opened = TRUE; |
477 | release_output_mutex (); | |
478 | } | |
479 | ||
480 | /* Duplicate tty handles. */ | |
481 | ||
482 | if (!get_ttyp ()->from_slave || !get_ttyp ()->to_slave) | |
483 | { | |
484 | termios_printf ("tty handles have been closed"); | |
485 | set_errno (EACCES); | |
486 | return 0; | |
487 | } | |
488 | ||
f449bfef | 489 | HANDLE from_master_local, to_master_local; |
1fd5e000 | 490 | |
f449bfef | 491 | if (!wincap.has_security () || |
1c001dd2 CS |
492 | cygserver_running == CYGSERVER_UNAVAIL || |
493 | !cygserver_attach_tty (&from_master_local, &to_master_local)) | |
1fd5e000 | 494 | { |
f449bfef RC |
495 | termios_printf ("cannot dup handles via server. using old method."); |
496 | ||
497 | HANDLE tty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE, | |
2402700d | 498 | get_ttyp ()->master_pid); |
f449bfef RC |
499 | termios_printf ("tty own handle %p",tty_owner); |
500 | if (tty_owner == NULL) | |
2402700d CF |
501 | { |
502 | termios_printf ("can't open tty (%d) handle process %d", | |
503 | ttynum, get_ttyp ()->master_pid); | |
504 | __seterrno (); | |
505 | return 0; | |
506 | } | |
507 | ||
508 | if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master, | |
509 | hMainProc, &from_master_local, 0, TRUE, | |
f449bfef | 510 | DUPLICATE_SAME_ACCESS)) |
2402700d CF |
511 | { |
512 | termios_printf ("can't duplicate input, %E"); | |
513 | __seterrno (); | |
514 | return 0; | |
515 | } | |
f449bfef | 516 | |
2402700d | 517 | if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master, |
f449bfef RC |
518 | hMainProc, &to_master_local, 0, TRUE, |
519 | DUPLICATE_SAME_ACCESS)) | |
2402700d CF |
520 | { |
521 | termios_printf ("can't duplicate output, %E"); | |
522 | __seterrno (); | |
523 | return 0; | |
524 | } | |
f449bfef | 525 | CloseHandle (tty_owner); |
1fd5e000 | 526 | } |
f449bfef RC |
527 | |
528 | termios_printf ("duplicated from_master %p->%p from tty_owner", | |
529 | get_ttyp ()->from_master, from_master_local); | |
530 | termios_printf ("duplicated to_master %p->%p from tty_owner", | |
531 | get_ttyp ()->to_master, to_master_local); | |
532 | ||
533 | set_io_handle (from_master_local); | |
f449bfef | 534 | set_output_handle (to_master_local); |
1fd5e000 | 535 | |
f3ea62a8 | 536 | set_open_status (); |
2116a175 | 537 | termios_printf ("tty%d opened", ttynum); |
1fd5e000 CF |
538 | |
539 | return 1; | |
540 | } | |
541 | ||
f449bfef RC |
542 | int |
543 | fhandler_tty_slave::cygserver_attach_tty (LPHANDLE from_master_ptr, | |
2402700d | 544 | LPHANDLE to_master_ptr) |
f449bfef RC |
545 | { |
546 | if (!from_master_ptr || !to_master_ptr) | |
547 | return 0; | |
548 | ||
1c001dd2 CS |
549 | client_request_attach_tty req ((DWORD) get_ttyp ()->master_pid, |
550 | (HANDLE) get_ttyp ()->from_master, | |
551 | (HANDLE) get_ttyp ()->to_master); | |
f449bfef | 552 | |
1c001dd2 | 553 | if (req.make_request () == -1 || req.error_code ()) |
f449bfef RC |
554 | return 0; |
555 | ||
1c001dd2 CS |
556 | *from_master_ptr = req.from_master (); |
557 | *to_master_ptr = req.to_master (); | |
f449bfef RC |
558 | return 1; |
559 | } | |
560 | ||
1fd5e000 | 561 | void |
9cec3d45 | 562 | fhandler_tty_slave::init (HANDLE, DWORD a, mode_t) |
1fd5e000 CF |
563 | { |
564 | int mode = 0; | |
565 | ||
566 | a &= GENERIC_READ | GENERIC_WRITE; | |
567 | if (a == GENERIC_READ) | |
568 | mode = O_RDONLY; | |
569 | if (a == GENERIC_WRITE) | |
570 | mode = O_WRONLY; | |
571 | if (a == (GENERIC_READ | GENERIC_WRITE)) | |
572 | mode = O_RDWR; | |
573 | ||
20a2c443 | 574 | open (0, mode); |
1fd5e000 CF |
575 | } |
576 | ||
577 | int | |
578 | fhandler_tty_slave::write (const void *ptr, size_t len) | |
579 | { | |
580 | DWORD n, towrite = len; | |
581 | ||
2116a175 | 582 | termios_printf ("tty%d, write(%x, %d)", ttynum, ptr, len); |
1fd5e000 CF |
583 | |
584 | acquire_output_mutex (INFINITE); | |
585 | ||
586 | while (len) | |
587 | { | |
588 | n = min (OUT_BUFFER_SIZE, len); | |
589 | char *buf = (char *)ptr; | |
590 | ptr = (char *) ptr + n; | |
591 | len -= n; | |
592 | ||
29ac7f89 CF |
593 | /* Previous write may have set write_error to != 0. Check it here. |
594 | This is less than optimal, but the alternative slows down tty | |
595 | writes enormously. */ | |
596 | if (get_ttyp ()->write_error) | |
597 | { | |
598 | set_errno (get_ttyp ()->write_error); | |
599 | towrite = (DWORD) -1; | |
600 | break; | |
601 | } | |
602 | ||
1fd5e000 CF |
603 | if (WriteFile (get_output_handle (), buf, n, &n, NULL) == FALSE) |
604 | { | |
d824bcf9 | 605 | DWORD err = GetLastError (); |
1fd5e000 | 606 | termios_printf ("WriteFile failed, %E"); |
d824bcf9 CF |
607 | switch (err) |
608 | { | |
609 | case ERROR_NO_DATA: | |
610 | err = ERROR_IO_DEVICE; | |
611 | default: | |
a3ad8241 | 612 | __seterrno_from_win_error (err); |
d824bcf9 | 613 | } |
1fd5e000 | 614 | _raise (SIGHUP); /* FIXME: Should this be SIGTTOU? */ |
d824bcf9 | 615 | towrite = (DWORD) -1; |
1fd5e000 CF |
616 | break; |
617 | } | |
618 | ||
619 | if (output_done_event != NULL) | |
620 | { | |
774ea162 CF |
621 | DWORD rc; |
622 | DWORD x = n * 1000; | |
623 | rc = WaitForSingleObject (output_done_event, x); | |
2116a175 | 624 | termios_printf ("waited %d ms for output_done_event, WFSO %d", x, rc); |
1fd5e000 | 625 | } |
1fd5e000 CF |
626 | } |
627 | release_output_mutex (); | |
628 | return towrite; | |
629 | } | |
630 | ||
a0626ebe | 631 | int __stdcall |
1fd5e000 CF |
632 | fhandler_tty_slave::read (void *ptr, size_t len) |
633 | { | |
634 | DWORD n; | |
635 | int totalread = 0; | |
636 | int vmin = INT_MAX; | |
637 | int vtime = 0; /* Initialized to prevent -Wuninitialized warning */ | |
306c4b67 ED |
638 | size_t readlen; |
639 | DWORD bytes_in_pipe; | |
1fd5e000 | 640 | char buf[INP_BUFFER_SIZE]; |
5e8e21d9 | 641 | char peek_buf[INP_BUFFER_SIZE]; |
306c4b67 ED |
642 | DWORD time_to_wait; |
643 | DWORD rc; | |
644 | HANDLE w4[2]; | |
1fd5e000 | 645 | |
f449bfef | 646 | termios_printf ("read(%x, %d) handle %p", ptr, len, get_handle ()); |
1fd5e000 CF |
647 | |
648 | if (!(get_ttyp ()->ti.c_lflag & ICANON)) | |
649 | { | |
2701126a CF |
650 | vmin = get_ttyp ()->ti.c_cc[VMIN]; |
651 | if (vmin > INP_BUFFER_SIZE) | |
652 | vmin = INP_BUFFER_SIZE; | |
1fd5e000 | 653 | vtime = get_ttyp ()->ti.c_cc[VTIME]; |
7a1174dc CF |
654 | if (vmin < 0) |
655 | vmin = 0; | |
656 | if (vtime < 0) | |
657 | vtime = 0; | |
658 | time_to_wait = vtime == 0 ? INFINITE : 100 * vtime; | |
1fd5e000 | 659 | } |
306c4b67 ED |
660 | else |
661 | time_to_wait = INFINITE; | |
662 | ||
663 | w4[0] = signal_arrived; | |
664 | w4[1] = input_available_event; | |
1fd5e000 CF |
665 | |
666 | while (len) | |
667 | { | |
306c4b67 ED |
668 | rc = WaitForMultipleObjects (2, w4, FALSE, time_to_wait); |
669 | if (rc == WAIT_OBJECT_0) | |
2116a175 | 670 | { |
ed4c976c | 671 | /* if we've received signal after successfully reading some data, |
2116a175 CF |
672 | just return all data successfully read */ |
673 | if (totalread > 0) | |
674 | break; | |
675 | set_sig_errno (EINTR); | |
676 | return -1; | |
677 | } | |
306c4b67 | 678 | else if (rc == WAIT_FAILED) |
2116a175 CF |
679 | { |
680 | termios_printf ("wait for input event failed, %E"); | |
681 | break; | |
682 | } | |
306c4b67 | 683 | else if (rc == WAIT_TIMEOUT) |
2116a175 | 684 | break; |
306c4b67 ED |
685 | rc = WaitForSingleObject (input_mutex, 1000); |
686 | if (rc == WAIT_FAILED) | |
2116a175 CF |
687 | { |
688 | termios_printf ("wait for input mutex failed, %E"); | |
689 | break; | |
690 | } | |
306c4b67 | 691 | else if (rc == WAIT_TIMEOUT) |
2116a175 CF |
692 | { |
693 | termios_printf ("failed to acquire input mutex after input event arrived"); | |
694 | break; | |
695 | } | |
c90e1cf1 | 696 | if (!PeekNamedPipe (get_handle (), peek_buf, sizeof (peek_buf), &bytes_in_pipe, NULL, NULL)) |
1fd5e000 | 697 | { |
306c4b67 | 698 | termios_printf ("PeekNamedPipe failed, %E"); |
2116a175 CF |
699 | _raise (SIGHUP); |
700 | bytes_in_pipe = 0; | |
1fd5e000 | 701 | } |
306c4b67 | 702 | readlen = min (bytes_in_pipe, min (len, sizeof (buf))); |
2116a175 CF |
703 | if (readlen) |
704 | { | |
705 | termios_printf ("reading %d bytes (vtime %d)", readlen, vtime); | |
706 | if (ReadFile (get_handle (), buf, readlen, &n, NULL) == FALSE) | |
707 | { | |
306c4b67 ED |
708 | termios_printf ("read failed, %E"); |
709 | _raise (SIGHUP); | |
710 | } | |
1ff9f4b9 CF |
711 | /* MSDN states that 5th prameter can be used to determine total |
712 | number of bytes in pipe, but for some reason this number doesn't | |
713 | change after successful read. So we have to peek into the pipe | |
714 | again to see if input is still available */ | |
715 | if (!PeekNamedPipe (get_handle (), peek_buf, 1, &bytes_in_pipe, NULL, NULL)) | |
5e8e21d9 ED |
716 | { |
717 | termios_printf ("PeekNamedPipe failed, %E"); | |
718 | _raise (SIGHUP); | |
719 | bytes_in_pipe = 0; | |
720 | } | |
2116a175 CF |
721 | if (n) |
722 | { | |
723 | len -= n; | |
724 | totalread += n; | |
725 | memcpy (ptr, buf, n); | |
726 | ptr = (char *) ptr + n; | |
727 | } | |
728 | } | |
306c4b67 | 729 | |
5e8e21d9 ED |
730 | if (!bytes_in_pipe) |
731 | ResetEvent (input_available_event); | |
306c4b67 ED |
732 | |
733 | ReleaseMutex (input_mutex); | |
3f0b4935 | 734 | |
1fd5e000 CF |
735 | if (get_ttyp ()->read_retval < 0) // read error |
736 | { | |
737 | set_errno (-get_ttyp ()->read_retval); | |
738 | totalread = -1; | |
739 | break; | |
740 | } | |
741 | if (get_ttyp ()->read_retval == 0) //EOF | |
742 | { | |
743 | termios_printf ("saw EOF"); | |
744 | break; | |
745 | } | |
5fd12fb0 | 746 | if (get_ttyp ()->ti.c_lflag & ICANON || is_nonblocking ()) |
1fd5e000 | 747 | break; |
306c4b67 | 748 | if (totalread >= vmin && (vmin > 0 || totalread > 0)) |
2116a175 | 749 | break; |
306c4b67 | 750 | |
2116a175 | 751 | /* vmin == 0 && vtime == 0: |
306c4b67 ED |
752 | * we've already read all input, if any, so return immediately |
753 | * vmin == 0 && vtime > 0: | |
754 | * we've waited for input 10*vtime ms in WFSO(input_available_event), | |
755 | * no matter whether any input arrived, we shouldn't wait any longer, | |
2116a175 | 756 | * so return immediately |
306c4b67 ED |
757 | * vmin > 0 && vtime == 0: |
758 | * here, totalread < vmin, so continue waiting until more data | |
759 | * arrive | |
760 | * vmin > 0 && vtime > 0: | |
761 | * similar to the previous here, totalread < vmin, and timer | |
762 | * hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT, | |
763 | * so "restart timer" and wait until more data arrive | |
764 | */ | |
765 | ||
2116a175 CF |
766 | if (vmin == 0) |
767 | break; | |
1fd5e000 CF |
768 | } |
769 | termios_printf ("%d=read(%x, %d)", totalread, ptr, len); | |
770 | return totalread; | |
771 | } | |
772 | ||
773 | int | |
774 | fhandler_tty_common::dup (fhandler_base *child) | |
775 | { | |
776 | fhandler_tty_slave *fts = (fhandler_tty_slave *) child; | |
777 | int errind; | |
778 | ||
1fd5e000 CF |
779 | fts->ttynum = ttynum; |
780 | fts->tcinit (get_ttyp ()); | |
781 | ||
782 | attach_tty (ttynum); | |
49a8c92c | 783 | tc->set_ctty (ttynum, openflags); |
1fd5e000 CF |
784 | |
785 | HANDLE nh; | |
786 | ||
787 | if (output_done_event == NULL) | |
788 | fts->output_done_event = NULL; | |
789 | else if (!DuplicateHandle (hMainProc, output_done_event, hMainProc, | |
790 | &fts->output_done_event, 0, 1, | |
791 | DUPLICATE_SAME_ACCESS)) | |
792 | { | |
793 | errind = 1; | |
794 | goto err; | |
795 | } | |
796 | if (ioctl_request_event == NULL) | |
797 | fts->ioctl_request_event = NULL; | |
798 | else if (!DuplicateHandle (hMainProc, ioctl_request_event, hMainProc, | |
799 | &fts->ioctl_request_event, 0, 1, | |
800 | DUPLICATE_SAME_ACCESS)) | |
801 | { | |
802 | errind = 2; | |
803 | goto err; | |
804 | } | |
805 | if (ioctl_done_event == NULL) | |
806 | fts->ioctl_done_event = NULL; | |
807 | else if (!DuplicateHandle (hMainProc, ioctl_done_event, hMainProc, | |
808 | &fts->ioctl_done_event, 0, 1, | |
809 | DUPLICATE_SAME_ACCESS)) | |
810 | { | |
811 | errind = 3; | |
812 | goto err; | |
813 | } | |
306c4b67 ED |
814 | if (!DuplicateHandle (hMainProc, input_available_event, hMainProc, |
815 | &fts->input_available_event, 0, 1, | |
816 | DUPLICATE_SAME_ACCESS)) | |
817 | { | |
818 | errind = 4; | |
819 | goto err; | |
820 | } | |
1fd5e000 CF |
821 | if (!DuplicateHandle (hMainProc, output_mutex, hMainProc, |
822 | &fts->output_mutex, 0, 1, | |
823 | DUPLICATE_SAME_ACCESS)) | |
824 | { | |
306c4b67 ED |
825 | errind = 5; |
826 | goto err; | |
827 | } | |
828 | if (!DuplicateHandle (hMainProc, input_mutex, hMainProc, | |
829 | &fts->input_mutex, 0, 1, | |
830 | DUPLICATE_SAME_ACCESS)) | |
831 | { | |
832 | errind = 6; | |
1fd5e000 CF |
833 | goto err; |
834 | } | |
835 | if (!DuplicateHandle (hMainProc, get_handle (), hMainProc, | |
836 | &nh, 0, 1, | |
837 | DUPLICATE_SAME_ACCESS)) | |
838 | { | |
306c4b67 | 839 | errind = 7; |
1fd5e000 CF |
840 | goto err; |
841 | } | |
842 | fts->set_io_handle (nh); | |
843 | ||
844 | if (!DuplicateHandle (hMainProc, get_output_handle (), hMainProc, | |
845 | &nh, 0, 1, | |
846 | DUPLICATE_SAME_ACCESS)) | |
847 | { | |
306c4b67 | 848 | errind = 8; |
1fd5e000 CF |
849 | goto err; |
850 | } | |
851 | fts->set_output_handle (nh); | |
852 | ||
853 | if (inuse == NULL) | |
854 | fts->inuse = NULL; | |
855 | else if (!DuplicateHandle (hMainProc, inuse, hMainProc, | |
856 | &fts->inuse, 0, 1, | |
857 | DUPLICATE_SAME_ACCESS)) | |
858 | { | |
306c4b67 | 859 | errind = 9; |
1fd5e000 CF |
860 | goto err; |
861 | } | |
862 | return 0; | |
863 | ||
864 | err: | |
865 | __seterrno (); | |
866 | termios_printf ("dup %d failed in DuplicateHandle, %E", errind); | |
867 | return -1; | |
868 | } | |
869 | ||
870 | int | |
871 | fhandler_tty_slave::tcgetattr (struct termios *t) | |
872 | { | |
873 | *t = get_ttyp ()->ti; | |
874 | return 0; | |
875 | } | |
876 | ||
877 | int | |
9cec3d45 | 878 | fhandler_tty_slave::tcsetattr (int, const struct termios *t) |
1fd5e000 CF |
879 | { |
880 | acquire_output_mutex (INFINITE); | |
881 | get_ttyp ()->ti = *t; | |
882 | release_output_mutex (); | |
883 | return 0; | |
884 | } | |
885 | ||
886 | int | |
9cec3d45 | 887 | fhandler_tty_slave::tcflush (int) |
1fd5e000 CF |
888 | { |
889 | return 0; | |
890 | } | |
891 | ||
1fd5e000 CF |
892 | int |
893 | fhandler_tty_slave::ioctl (unsigned int cmd, void *arg) | |
894 | { | |
895 | termios_printf ("ioctl (%x)", cmd); | |
896 | ||
7a1174dc CF |
897 | if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid |
898 | && myself->ctty == ttynum && (get_ttyp ()->ti.c_lflag & TOSTOP)) | |
1fd5e000 CF |
899 | { |
900 | /* background process */ | |
2116a175 CF |
901 | termios_printf ("bg ioctl pgid %d, tpgid %d, ctty %d", |
902 | myself->pgid, get_ttyp ()->getpgid (), myself->ctty); | |
1fd5e000 CF |
903 | _raise (SIGTTOU); |
904 | } | |
ad0bed74 | 905 | |
1fd5e000 CF |
906 | switch (cmd) |
907 | { | |
908 | case TIOCGWINSZ: | |
1fd5e000 | 909 | case TIOCSWINSZ: |
1fd5e000 CF |
910 | break; |
911 | case FIONBIO: | |
5fd12fb0 | 912 | set_nonblocking (*(int *) arg); |
ad0bed74 | 913 | goto out; |
1fd5e000 CF |
914 | default: |
915 | set_errno (EINVAL); | |
916 | return -1; | |
917 | } | |
ad0bed74 CF |
918 | |
919 | acquire_output_mutex (INFINITE); | |
920 | ||
921 | get_ttyp ()->cmd = cmd; | |
922 | get_ttyp ()->ioctl_retval = 0; | |
923 | switch (cmd) | |
924 | { | |
925 | case TIOCGWINSZ: | |
926 | get_ttyp ()->arg.winsize = get_ttyp ()->winsize; | |
927 | if (ioctl_request_event) | |
928 | SetEvent (ioctl_request_event); | |
929 | * (struct winsize *) arg = get_ttyp ()->arg.winsize; | |
930 | if (ioctl_done_event) | |
931 | WaitForSingleObject (ioctl_done_event, INFINITE); | |
932 | get_ttyp ()->winsize = get_ttyp ()->arg.winsize; | |
933 | break; | |
934 | case TIOCSWINSZ: | |
935 | get_ttyp ()->ioctl_retval = -1; | |
936 | get_ttyp ()->arg.winsize = * (struct winsize *) arg; | |
937 | if (ioctl_request_event) | |
938 | SetEvent (ioctl_request_event); | |
939 | if (ioctl_done_event) | |
940 | WaitForSingleObject (ioctl_done_event, INFINITE); | |
941 | break; | |
942 | } | |
943 | ||
944 | release_output_mutex (); | |
945 | ||
946 | out: | |
1fd5e000 CF |
947 | termios_printf ("%d = ioctl (%x)", get_ttyp ()->ioctl_retval, cmd); |
948 | return get_ttyp ()->ioctl_retval; | |
949 | } | |
950 | ||
951 | /******************************************************* | |
952 | fhandler_pty_master | |
953 | */ | |
0476bae5 CF |
954 | fhandler_pty_master::fhandler_pty_master (DWORD devtype, int unit) |
955 | : fhandler_tty_common (devtype, unit) | |
1fd5e000 | 956 | { |
1fd5e000 CF |
957 | } |
958 | ||
959 | int | |
8af0f81d | 960 | fhandler_pty_master::open (path_conv *, int flags, mode_t) |
1fd5e000 CF |
961 | { |
962 | ttynum = cygwin_shared->tty.allocate_tty (0); | |
963 | if (ttynum < 0) | |
964 | return 0; | |
965 | ||
966 | cygwin_shared->tty[ttynum]->common_init (this); | |
2496a363 | 967 | inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE); |
1bc9effd | 968 | set_flags ((flags & ~O_TEXT) | O_BINARY); |
f3ea62a8 | 969 | set_open_status (); |
1fd5e000 CF |
970 | |
971 | termios_printf ("opened pty master tty%d<%p>", ttynum, this); | |
972 | return 1; | |
973 | } | |
974 | ||
975 | int | |
976 | fhandler_tty_common::close () | |
977 | { | |
1fd5e000 CF |
978 | if (output_done_event && !CloseHandle (output_done_event)) |
979 | termios_printf ("CloseHandle (output_done_event), %E"); | |
980 | if (ioctl_done_event && !CloseHandle (ioctl_done_event)) | |
981 | termios_printf ("CloseHandle (ioctl_done_event), %E"); | |
982 | if (ioctl_request_event && !CloseHandle (ioctl_request_event)) | |
983 | termios_printf ("CloseHandle (ioctl_request_event), %E"); | |
1fd5e000 CF |
984 | if (inuse && !CloseHandle (inuse)) |
985 | termios_printf ("CloseHandle (inuse), %E"); | |
306c4b67 ED |
986 | if (!ForceCloseHandle (input_mutex)) |
987 | termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex); | |
083abe54 CF |
988 | if (!ForceCloseHandle (output_mutex)) |
989 | termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex); | |
78ace8a7 ED |
990 | |
991 | /* Send EOF to slaves if master side is closed */ | |
992 | if (!get_ttyp ()->master_alive ()) | |
993 | { | |
994 | termios_printf ("no more masters left. sending EOF" ); | |
995 | SetEvent (input_available_event); | |
996 | } | |
997 | ||
306c4b67 ED |
998 | if (!ForceCloseHandle (input_available_event)) |
999 | termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event); | |
92e19690 | 1000 | if (!ForceCloseHandle1 (get_handle (), from_pty)) |
1fd5e000 | 1001 | termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ()); |
92e19690 | 1002 | if (!ForceCloseHandle1 (get_output_handle (), to_pty)) |
1fd5e000 CF |
1003 | termios_printf ("CloseHandle (get_output_handle ()<%p>), %E", get_output_handle ()); |
1004 | ||
1005 | inuse = NULL; | |
a7670c1e | 1006 | termios_printf ("tty%d <%p,%p> closed", ttynum, get_handle (), get_output_handle ()); |
1fd5e000 CF |
1007 | return 0; |
1008 | } | |
1009 | ||
1010 | int | |
1011 | fhandler_pty_master::close () | |
1012 | { | |
1013 | #if 0 | |
1014 | while (accept_input () > 0) | |
1015 | continue; | |
1016 | #endif | |
1017 | this->fhandler_tty_common::close (); | |
1018 | ||
1019 | if (!get_ttyp ()->master_alive ()) | |
1020 | { | |
1021 | termios_printf ("freeing tty%d (%d)", ttynum, get_ttyp ()->ntty); | |
92e19690 | 1022 | #if 0 |
1fd5e000 | 1023 | if (get_ttyp ()->to_slave) |
92e19690 | 1024 | ForceCloseHandle1 (get_ttyp ()->to_slave, to_slave); |
1fd5e000 | 1025 | if (get_ttyp ()->from_slave) |
92e19690 CF |
1026 | ForceCloseHandle1 (get_ttyp ()->from_slave, from_slave); |
1027 | #endif | |
1fd5e000 CF |
1028 | if (get_ttyp ()->from_master) |
1029 | CloseHandle (get_ttyp ()->from_master); | |
1030 | if (get_ttyp ()->to_master) | |
1031 | CloseHandle (get_ttyp ()->to_master); | |
1032 | get_ttyp ()->init (); | |
1033 | } | |
1034 | ||
1035 | return 0; | |
1036 | } | |
1037 | ||
1038 | int | |
1039 | fhandler_pty_master::write (const void *ptr, size_t len) | |
1040 | { | |
95a8465b | 1041 | (void) line_edit ((char *) ptr, len); |
1fd5e000 CF |
1042 | return len; |
1043 | } | |
1044 | ||
a0626ebe | 1045 | int __stdcall |
1fd5e000 CF |
1046 | fhandler_pty_master::read (void *ptr, size_t len) |
1047 | { | |
29ac7f89 | 1048 | return process_slave_output ((char *) ptr, len, pktmode); |
1fd5e000 CF |
1049 | } |
1050 | ||
1051 | int | |
1052 | fhandler_pty_master::tcgetattr (struct termios *t) | |
1053 | { | |
1054 | *t = cygwin_shared->tty[ttynum]->ti; | |
1055 | return 0; | |
1056 | } | |
1057 | ||
1058 | int | |
9cec3d45 | 1059 | fhandler_pty_master::tcsetattr (int, const struct termios *t) |
1fd5e000 CF |
1060 | { |
1061 | cygwin_shared->tty[ttynum]->ti = *t; | |
1062 | return 0; | |
1063 | } | |
1064 | ||
1065 | int | |
9cec3d45 | 1066 | fhandler_pty_master::tcflush (int) |
1fd5e000 CF |
1067 | { |
1068 | return 0; | |
1069 | } | |
1070 | ||
1071 | int | |
1072 | fhandler_pty_master::ioctl (unsigned int cmd, void *arg) | |
1073 | { | |
1074 | switch (cmd) | |
1075 | { | |
1076 | case TIOCPKT: | |
1077 | pktmode = * (int *) arg; | |
1078 | break; | |
1079 | case TIOCGWINSZ: | |
1080 | * (struct winsize *) arg = get_ttyp ()->winsize; | |
1081 | break; | |
1082 | case TIOCSWINSZ: | |
1083 | get_ttyp ()->winsize = * (struct winsize *) arg; | |
1084 | _kill (-get_ttyp ()->getpgid (), SIGWINCH); | |
1085 | break; | |
1086 | case FIONBIO: | |
5fd12fb0 | 1087 | set_nonblocking (*(int *) arg); |
1fd5e000 CF |
1088 | break; |
1089 | default: | |
1090 | set_errno (EINVAL); | |
1091 | return -1; | |
1092 | } | |
1093 | return 0; | |
1094 | } | |
1095 | ||
1096 | char * | |
1097 | fhandler_pty_master::ptsname (void) | |
1098 | { | |
1099 | static char buf[32]; | |
1100 | ||
1101 | __small_sprintf (buf, "/dev/tty%d", ttynum); | |
1102 | return buf; | |
1103 | } | |
1104 | ||
1105 | void | |
1106 | fhandler_tty_common::set_close_on_exec (int val) | |
1107 | { | |
2116a175 | 1108 | #ifndef DEBUGGING |
1fd5e000 | 1109 | this->fhandler_base::set_close_on_exec (val); |
2116a175 CF |
1110 | #else |
1111 | /* FIXME: This is a duplication from fhandler_base::set_close_on_exec. | |
1112 | It is here because we need to specify the "from_pty" stuff here or | |
1113 | we'll get warnings from ForceCloseHandle when debugging. */ | |
c50d56bc | 1114 | set_inheritance (get_io_handle (), val); |
2116a175 CF |
1115 | set_close_on_exec_flag (val); |
1116 | #endif | |
1fd5e000 CF |
1117 | if (output_done_event) |
1118 | set_inheritance (output_done_event, val); | |
1119 | if (ioctl_request_event) | |
1120 | set_inheritance (ioctl_request_event, val); | |
1121 | if (ioctl_done_event) | |
1122 | set_inheritance (ioctl_done_event, val); | |
1123 | if (inuse) | |
1124 | set_inheritance (inuse, val); | |
c50d56bc CF |
1125 | set_inheritance (output_mutex, val); |
1126 | set_inheritance (input_mutex, val); | |
306c4b67 | 1127 | set_inheritance (input_available_event, val); |
c50d56bc | 1128 | set_inheritance (output_handle, val); |
1fd5e000 CF |
1129 | } |
1130 | ||
1131 | void | |
1132 | fhandler_tty_common::fixup_after_fork (HANDLE parent) | |
1133 | { | |
e935fcf0 | 1134 | this->fhandler_termios::fixup_after_fork (parent); |
1fd5e000 CF |
1135 | if (output_done_event) |
1136 | fork_fixup (parent, output_done_event, "output_done_event"); | |
1137 | if (ioctl_request_event) | |
1138 | fork_fixup (parent, ioctl_request_event, "ioctl_request_event"); | |
1139 | if (ioctl_done_event) | |
1140 | fork_fixup (parent, ioctl_done_event, "ioctl_done_event"); | |
1141 | if (output_mutex) | |
a448b8cf | 1142 | fork_fixup (parent, output_mutex, "output_mutex"); |
306c4b67 | 1143 | if (input_mutex) |
a448b8cf | 1144 | fork_fixup (parent, input_mutex, "input_mutex"); |
306c4b67 ED |
1145 | if (input_available_event) |
1146 | fork_fixup (parent, input_available_event, "input_available_event"); | |
1fd5e000 CF |
1147 | fork_fixup (parent, inuse, "inuse"); |
1148 | } | |
1149 | ||
1150 | void | |
1151 | fhandler_pty_master::set_close_on_exec (int val) | |
1152 | { | |
1153 | this->fhandler_tty_common::set_close_on_exec (val); | |
1fd5e000 CF |
1154 | |
1155 | /* FIXME: There is a console handle leak here. */ | |
1156 | if (get_ttyp ()->master_pid == GetCurrentProcessId ()) | |
1157 | { | |
1158 | get_ttyp ()->from_slave = get_handle (); | |
1159 | get_ttyp ()->to_slave = get_output_handle (); | |
92e19690 CF |
1160 | termios_printf ("from_slave %p, to_slave %p", get_handle (), |
1161 | get_output_handle ()); | |
1fd5e000 CF |
1162 | } |
1163 | } | |
1164 | ||
1fd5e000 CF |
1165 | void |
1166 | fhandler_tty_master::fixup_after_fork (HANDLE child) | |
1167 | { | |
1168 | this->fhandler_pty_master::fixup_after_fork (child); | |
1169 | console->fixup_after_fork (child); | |
6b2a9a2f | 1170 | output_thread = NULL; // It's unreachable now |
1fd5e000 CF |
1171 | } |
1172 | ||
b0e82b74 CF |
1173 | void |
1174 | fhandler_tty_master::fixup_after_exec (HANDLE) | |
1fd5e000 | 1175 | { |
1fd5e000 CF |
1176 | console->close (); |
1177 | init_console (); | |
6b2a9a2f | 1178 | output_thread = NULL; // It's unreachable now |
1fd5e000 CF |
1179 | } |
1180 | ||
1181 | int | |
1182 | fhandler_tty_master::init_console () | |
1183 | { | |
0381fec6 | 1184 | console = (fhandler_console *) cygheap->fdtab.build_fhandler (-1, FH_CONSOLE, "/dev/ttym"); |
1fd5e000 CF |
1185 | if (console == NULL) |
1186 | return -1; | |
1187 | ||
1188 | console->init (INVALID_HANDLE_VALUE, GENERIC_READ | GENERIC_WRITE, O_BINARY); | |
1189 | console->set_r_no_interrupt (1); | |
1190 | return 0; | |
1191 | } |