]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/fhandler_tty.cc
* environ.cc (environ_init): Avoid a compiler warning.
[newlib-cygwin.git] / winsup / cygwin / fhandler_tty.cc
CommitLineData
1fd5e000
CF
1/* fhandler_tty.cc
2
ce006ffa 3 Copyright 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
1fd5e000
CF
4
5This file is part of Cygwin.
6
7This software is a copyrighted work licensed under the terms of the
8Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9details. */
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
32fhandler_tty_master NO_COPY *tty_master;
33
34static DWORD WINAPI process_input (void *); // Input queue thread
35static DWORD WINAPI process_output (void *); // Output queue thread
36static DWORD WINAPI process_ioctl (void *); // Ioctl requests thread
37
711ded6d 38fhandler_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
43int
44fhandler_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
78static class mutex_stack
79{
80public:
81 const char *fn;
82 int ln;
83 const char *tname;
84} ostack[100];
85
08b78edf 86static int osi;
1fd5e000
CF
87#endif /*DEBUGGING*/
88
89DWORD
90fhandler_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
112void
113fhandler_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
132void
133fhandler_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
142int
143fhandler_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
187static DWORD WINAPI
9cec3d45 188process_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 200bool
1fd5e000
CF
201fhandler_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
216int
3f0b4935 217fhandler_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
365out:
366 termios_printf ("returning %d", rc);
367 return rc;
1fd5e000
CF
368}
369
370static DWORD WINAPI
1524ae42 371process_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
394static DWORD WINAPI
9cec3d45 395process_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
411fhandler_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
417fhandler_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 425int
8af0f81d 426fhandler_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
542int
543fhandler_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 561void
9cec3d45 562fhandler_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
577int
578fhandler_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 631int __stdcall
1fd5e000
CF
632fhandler_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
773int
774fhandler_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
864err:
865 __seterrno ();
866 termios_printf ("dup %d failed in DuplicateHandle, %E", errind);
867 return -1;
868}
869
870int
871fhandler_tty_slave::tcgetattr (struct termios *t)
872{
873 *t = get_ttyp ()->ti;
874 return 0;
875}
876
877int
9cec3d45 878fhandler_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
886int
9cec3d45 887fhandler_tty_slave::tcflush (int)
1fd5e000
CF
888{
889 return 0;
890}
891
1fd5e000
CF
892int
893fhandler_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
946out:
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
954fhandler_pty_master::fhandler_pty_master (DWORD devtype, int unit)
955 : fhandler_tty_common (devtype, unit)
1fd5e000 956{
1fd5e000
CF
957}
958
959int
8af0f81d 960fhandler_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
975int
976fhandler_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
1010int
1011fhandler_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
1038int
1039fhandler_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 1045int __stdcall
1fd5e000
CF
1046fhandler_pty_master::read (void *ptr, size_t len)
1047{
29ac7f89 1048 return process_slave_output ((char *) ptr, len, pktmode);
1fd5e000
CF
1049}
1050
1051int
1052fhandler_pty_master::tcgetattr (struct termios *t)
1053{
1054 *t = cygwin_shared->tty[ttynum]->ti;
1055 return 0;
1056}
1057
1058int
9cec3d45 1059fhandler_pty_master::tcsetattr (int, const struct termios *t)
1fd5e000
CF
1060{
1061 cygwin_shared->tty[ttynum]->ti = *t;
1062 return 0;
1063}
1064
1065int
9cec3d45 1066fhandler_pty_master::tcflush (int)
1fd5e000
CF
1067{
1068 return 0;
1069}
1070
1071int
1072fhandler_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
1096char *
1097fhandler_pty_master::ptsname (void)
1098{
1099 static char buf[32];
1100
1101 __small_sprintf (buf, "/dev/tty%d", ttynum);
1102 return buf;
1103}
1104
1105void
1106fhandler_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
1131void
1132fhandler_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
1150void
1151fhandler_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
1165void
1166fhandler_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
1173void
1174fhandler_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
1181int
1182fhandler_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}
This page took 0.258412 seconds and 5 git commands to generate.