OSDN Git Service

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