1232 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			1232 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* fhandler_tty.cc
 | |
| 
 | |
|    Copyright 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
 | |
| 
 | |
| This file is part of Cygwin.
 | |
| 
 | |
| This software is a copyrighted work licensed under the terms of the
 | |
| Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 | |
| details. */
 | |
| 
 | |
| #include "winsup.h"
 | |
| #include <stdio.h>
 | |
| #include <unistd.h>
 | |
| #include <stdlib.h>
 | |
| #include <errno.h>
 | |
| #include <ctype.h>
 | |
| #include <limits.h>
 | |
| #include "cygerrno.h"
 | |
| #include "security.h"
 | |
| #include "fhandler.h"
 | |
| #include "path.h"
 | |
| #include "dtable.h"
 | |
| #include "sigproc.h"
 | |
| #include "pinfo.h"
 | |
| #include "cygheap.h"
 | |
| #include "shared_info.h"
 | |
| #include "cygwin/cygserver_transport.h"
 | |
| #include "cygwin/cygserver.h"
 | |
| 
 | |
| /* Tty master stuff */
 | |
| 
 | |
| fhandler_tty_master NO_COPY *tty_master;
 | |
| 
 | |
| static DWORD WINAPI process_input (void *);		// Input queue thread
 | |
| static DWORD WINAPI process_output (void *);		// Output queue thread
 | |
| static DWORD WINAPI process_ioctl (void *);		// Ioctl requests thread
 | |
| 
 | |
| fhandler_tty_master::fhandler_tty_master (int unit)
 | |
|   : fhandler_pty_master (FH_TTYM, unit), console (NULL), hThread (NULL)
 | |
| {
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_tty_master::init (int ntty)
 | |
| {
 | |
|   HANDLE h;
 | |
|   termios_printf ("Creating master for tty%d", ntty);
 | |
| 
 | |
|   if (init_console ())
 | |
|     {
 | |
|       termios_printf ("can't create fhandler");
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|   termios ti;
 | |
|   memset (&ti, 0, sizeof (ti));
 | |
|   console->tcsetattr (0, &ti);
 | |
| 
 | |
|   ttynum = ntty;
 | |
| 
 | |
|   cygwin_shared->tty[ttynum]->common_init (this);
 | |
| 
 | |
|   inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE);
 | |
| 
 | |
|   h = makethread (process_input, NULL, 0, "ttyin");
 | |
|   if (h == NULL)
 | |
|     {
 | |
|       termios_printf ("can't create input thread");
 | |
|       return -1;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       SetThreadPriority (h, THREAD_PRIORITY_HIGHEST);
 | |
|       CloseHandle (h);
 | |
|     }
 | |
| 
 | |
|   h = makethread (process_ioctl, NULL, 0, "ttyioctl");
 | |
|   if (h == NULL)
 | |
|     {
 | |
|       termios_printf ("can't create ioctl thread");
 | |
|       return -1;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       SetThreadPriority (h, THREAD_PRIORITY_HIGHEST);
 | |
|       CloseHandle (h);
 | |
|     }
 | |
| 
 | |
|   hThread = makethread (process_output, NULL, 0, "ttyout");
 | |
|   if (hThread != NULL)
 | |
|     SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST);
 | |
|   else
 | |
|     {
 | |
|       termios_printf ("can't create output thread");
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| #ifdef DEBUGGING
 | |
| static class mutex_stack
 | |
| {
 | |
| public:
 | |
|   const char *fn;
 | |
|   int ln;
 | |
|   const char *tname;
 | |
| } ostack[100];
 | |
| 
 | |
| static int osi;
 | |
| #endif /*DEBUGGING*/
 | |
| 
 | |
| DWORD
 | |
| fhandler_tty_common::__acquire_output_mutex (const char *fn, int ln,
 | |
| 					   DWORD ms)
 | |
| {
 | |
|   if (strace.active)
 | |
|     strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: waiting %d ms", ln, ms);
 | |
|   DWORD res = WaitForSingleObject (output_mutex, ms);
 | |
|   if (res == WAIT_OBJECT_0)
 | |
|     {
 | |
| #ifndef DEBUGGING
 | |
|       if (strace.active)
 | |
| 	strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: acquired", ln, res);
 | |
| #else
 | |
|       ostack[osi].fn = fn;
 | |
|       ostack[osi].ln = ln;
 | |
|       ostack[osi].tname = threadname (0, 0);
 | |
|       termios_printf ("acquired for %s:%d, osi %d", fn, ln, osi);
 | |
|       osi++;
 | |
| #endif
 | |
|     }
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| void
 | |
| fhandler_tty_common::__release_output_mutex (const char *fn, int ln)
 | |
| {
 | |
|   if (ReleaseMutex (output_mutex))
 | |
|     {
 | |
| #ifndef DEBUGGING
 | |
|       if (strace.active)
 | |
| 	strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex released", ln);
 | |
| #else
 | |
|       if (osi > 0)
 | |
| 	osi--;
 | |
|       termios_printf ("released at %s:%d, osi %d", fn, ln, osi);
 | |
|       termios_printf ("  for %s:%d (%s)", ostack[osi].fn, ostack[osi].ln, ostack[osi].tname);
 | |
|       ostack[osi].ln = -ln;
 | |
| #endif
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Process tty input. */
 | |
| 
 | |
| void
 | |
| fhandler_pty_master::doecho (const void *str, DWORD len)
 | |
| {
 | |
|   acquire_output_mutex (INFINITE);
 | |
|   if (!WriteFile (get_ttyp ()->to_master, str, len, &len, NULL))
 | |
|     termios_printf ("Write to %p failed, %E", get_ttyp ()->to_master);
 | |
| //  WaitForSingleObject (output_done_event, INFINITE);
 | |
|   release_output_mutex ();
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_pty_master::accept_input ()
 | |
| {
 | |
|   DWORD bytes_left, written;
 | |
|   DWORD n;
 | |
|   DWORD rc;
 | |
|   char* p;
 | |
| 
 | |
|   rc = WaitForSingleObject (input_mutex, INFINITE);
 | |
| 
 | |
|   bytes_left = n = eat_readahead (-1);
 | |
|   get_ttyp ()->read_retval = 0;
 | |
|   p = rabuf;
 | |
| 
 | |
|   if (n != 0)
 | |
|     {
 | |
|       while (bytes_left > 0)
 | |
| 	{
 | |
| 	  termios_printf ("about to write %d chars to slave", bytes_left);
 | |
| 	  rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
 | |
| 	  if (!rc)
 | |
| 	    {
 | |
| 	      debug_printf ("error writing to pipe %E");
 | |
| 	      break;
 | |
| 	    }
 | |
| 	  get_ttyp ()->read_retval += written;
 | |
| 	  p += written;
 | |
| 	  bytes_left -= written;
 | |
| 	  if (bytes_left > 0)
 | |
| 	    {
 | |
| 	      debug_printf ("to_slave pipe is full");
 | |
| 	      SetEvent (input_available_event);
 | |
| 	      ReleaseMutex (input_mutex);
 | |
| 	      Sleep (10);
 | |
| 	      rc = WaitForSingleObject (input_mutex, INFINITE);
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|   else
 | |
|     termios_printf ("sending EOF to slave");
 | |
|   SetEvent (input_available_event);
 | |
|   ReleaseMutex (input_mutex);
 | |
|   return get_ttyp ()->read_retval;
 | |
| }
 | |
| 
 | |
| static DWORD WINAPI
 | |
| process_input (void *)
 | |
| {
 | |
|   char rawbuf[INP_BUFFER_SIZE];
 | |
| 
 | |
|   while (1)
 | |
|     {
 | |
|       int nraw = tty_master->console->read ((void *) rawbuf,
 | |
| 				      (size_t) INP_BUFFER_SIZE);
 | |
|       (void) tty_master->line_edit (rawbuf, nraw);
 | |
|     }
 | |
| }
 | |
| 
 | |
| bool
 | |
| fhandler_pty_master::hit_eof ()
 | |
| {
 | |
|   if (get_ttyp ()->was_opened && !get_ttyp ()->slave_alive ())
 | |
|     {
 | |
|       /* We have the only remaining open handle to this pty, and
 | |
| 	 the slave pty has been opened at least once.  We treat
 | |
| 	 this as EOF.  */
 | |
|       termios_printf ("all other handles closed");
 | |
|       return 1;
 | |
|     }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* Process tty output requests */
 | |
| 
 | |
| int
 | |
| fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on)
 | |
| {
 | |
|   size_t rlen;
 | |
|   char outbuf[OUT_BUFFER_SIZE + 1];
 | |
|   DWORD n;
 | |
|   int column = 0;
 | |
|   int rc = 0;
 | |
| 
 | |
|   if (len == 0)
 | |
|     goto out;
 | |
| 
 | |
|   if (need_nl)
 | |
|     {
 | |
|       /* We need to return a left over \n character, resulting from
 | |
| 	 \r\n conversion.  Note that we already checked for FLUSHO and
 | |
| 	 output_stopped at the time that we read the character, so we
 | |
| 	 don't check again here.  */
 | |
|       buf[0] = '\n';
 | |
|       need_nl = 0;
 | |
|       rc = 1;
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
| 
 | |
|   for (;;)
 | |
|     {
 | |
|       /* Set RLEN to the number of bytes to read from the pipe.  */
 | |
|       rlen = len;
 | |
|       if (get_ttyp ()->ti.c_oflag & OPOST && get_ttyp ()->ti.c_oflag & ONLCR)
 | |
| 	{
 | |
| 	  /* We are going to expand \n to \r\n, so don't read more than
 | |
| 	     half of the number of bytes requested.  */
 | |
| 	  rlen /= 2;
 | |
| 	  if (rlen == 0)
 | |
| 	    rlen = 1;
 | |
| 	}
 | |
|       if (rlen > sizeof outbuf)
 | |
| 	rlen = sizeof outbuf;
 | |
| 
 | |
|       HANDLE handle = get_io_handle ();
 | |
| 
 | |
|       n = 0; // get_readahead_into_buffer (outbuf, len);
 | |
|       if (!n)
 | |
| 	{
 | |
| 	  /* Doing a busy wait like this is quite inefficient, but nothing
 | |
| 	     else seems to work completely.  Windows should provide some sort
 | |
| 	     of overlapped I/O for pipes, or something, but it doesn't.  */
 | |
| 	  while (1)
 | |
| 	    {
 | |
| 	      if (!PeekNamedPipe (handle, NULL, 0, NULL, &n, NULL))
 | |
| 		goto err;
 | |
| 	      if (n > 0)
 | |
| 		break;
 | |
| 	      if (hit_eof ())
 | |
| 		goto out;
 | |
| 	      if (n == 0 && is_nonblocking ())
 | |
| 		{
 | |
| 		  set_errno (EAGAIN);
 | |
| 		  rc = -1;
 | |
| 		  break;
 | |
| 		}
 | |
| 
 | |
| 	      Sleep (10);
 | |
| 	    }
 | |
| 
 | |
| 	  if (ReadFile (handle, outbuf, rlen, &n, NULL) == FALSE)
 | |
| 	    goto err;
 | |
| 	}
 | |
| 
 | |
|       termios_printf ("bytes read %u", n);
 | |
|       get_ttyp ()->write_error = 0;
 | |
|       if (output_done_event != NULL)
 | |
| 	SetEvent (output_done_event);
 | |
| 
 | |
|       if (get_ttyp ()->ti.c_lflag & FLUSHO)
 | |
| 	continue;
 | |
| 
 | |
|       char *optr;
 | |
|       optr = buf;
 | |
|       if (pktmode_on)
 | |
| 	*optr++ = TIOCPKT_DATA;
 | |
| 
 | |
|       if (!(get_ttyp ()->ti.c_oflag & OPOST))	// post-process output
 | |
| 	{
 | |
| 	  memcpy (optr, outbuf, n);
 | |
| 	  optr += n;
 | |
| 	}
 | |
|       else					// raw output mode
 | |
| 	{
 | |
| 	  char *iptr = outbuf;
 | |
| 
 | |
| 	  while (n--)
 | |
| 	    {
 | |
| 	      switch (*iptr)
 | |
| 		{
 | |
| 		case '\r':
 | |
| 		  if ((get_ttyp ()->ti.c_oflag & ONOCR) && column == 0)
 | |
| 		    {
 | |
| 		      iptr++;
 | |
| 		      continue;
 | |
| 		    }
 | |
| 		  if (get_ttyp ()->ti.c_oflag & OCRNL)
 | |
| 		    *iptr = '\n';
 | |
| 		  else
 | |
| 		    column = 0;
 | |
| 		  break;
 | |
| 		case '\n':
 | |
| 		  if (get_ttyp ()->ti.c_oflag & ONLCR)
 | |
| 		    {
 | |
| 		      *optr++ = '\r';
 | |
| 		      column = 0;
 | |
| 		    }
 | |
| 		  if (get_ttyp ()->ti.c_oflag & ONLRET)
 | |
| 		    column = 0;
 | |
| 		  break;
 | |
| 		default:
 | |
| 		  column++;
 | |
| 		  break;
 | |
| 		}
 | |
| 
 | |
| 	      /* Don't store data past the end of the user's buffer.  This
 | |
| 		 can happen if the user requests a read of 1 byte when
 | |
| 		 doing \r\n expansion.  */
 | |
| 	      if (optr - buf >= (int) len)
 | |
| 		{
 | |
| 		  if (*iptr != '\n' || n != 0)
 | |
| 		    system_printf ("internal error: %d unexpected characters", n);
 | |
| 		  need_nl = 1;
 | |
| 		  break;
 | |
| 		}
 | |
| 
 | |
| 	      *optr++ = *iptr++;
 | |
| 	    }
 | |
| 	}
 | |
|       rc = optr - buf;
 | |
|       break;
 | |
| 
 | |
|     err:
 | |
|       if (GetLastError () == ERROR_BROKEN_PIPE)
 | |
| 	rc = 0;
 | |
|       else
 | |
| 	{
 | |
| 	  __seterrno ();
 | |
| 	  rc = -1;
 | |
| 	}
 | |
|       break;
 | |
|     }
 | |
| 
 | |
| out:
 | |
|   termios_printf ("returning %d", rc);
 | |
|   return rc;
 | |
| }
 | |
| 
 | |
| static DWORD WINAPI
 | |
| process_output (void *)
 | |
| {
 | |
|   char buf[OUT_BUFFER_SIZE*2];
 | |
| 
 | |
|   for (;;)
 | |
|     {
 | |
|       int n = tty_master->process_slave_output (buf, OUT_BUFFER_SIZE, 0);
 | |
|       if (n < 0)
 | |
| 	{
 | |
| 	  termios_printf ("ReadFile %E");
 | |
| 	  ExitThread (0);
 | |
| 	}
 | |
|       if (n == 0)
 | |
| 	{
 | |
| 	  /* End of file.  */
 | |
| 	  ExitThread (0);
 | |
| 	}
 | |
|       n = tty_master->console->write ((void *) buf, (size_t) n);
 | |
|       tty_master->get_ttyp ()->write_error = n == -1 ? get_errno () : 0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Process tty ioctl requests */
 | |
| 
 | |
| static DWORD WINAPI
 | |
| process_ioctl (void *)
 | |
| {
 | |
|   while (1)
 | |
|     {
 | |
|       WaitForSingleObject (tty_master->ioctl_request_event, INFINITE);
 | |
|       termios_printf ("ioctl() request");
 | |
|       tty_master->get_ttyp ()->ioctl_retval =
 | |
|       tty_master->console->ioctl (tty_master->get_ttyp ()->cmd,
 | |
| 			     (void *) &tty_master->get_ttyp ()->arg);
 | |
|       SetEvent (tty_master->ioctl_done_event);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**********************************************************************/
 | |
| /* Tty slave stuff */
 | |
| 
 | |
| fhandler_tty_slave::fhandler_tty_slave (int num)
 | |
|   : fhandler_tty_common (FH_TTYS, num)
 | |
| {
 | |
| }
 | |
| 
 | |
| fhandler_tty_slave::fhandler_tty_slave ()
 | |
|   : fhandler_tty_common (FH_TTYS, 0)
 | |
| {
 | |
| }
 | |
| 
 | |
| /* FIXME: This function needs to close handles when it has
 | |
|    a failing condition. */
 | |
| int
 | |
| fhandler_tty_slave::open (path_conv *, int flags, mode_t)
 | |
| {
 | |
|   tcinit (cygwin_shared->tty[ttynum]);
 | |
| 
 | |
|   attach_tty (ttynum);
 | |
|   tc->set_ctty (ttynum, flags);
 | |
| 
 | |
|   set_flags ((flags & ~O_TEXT) | O_BINARY);
 | |
|   /* Create synchronisation events */
 | |
|   char buf[40];
 | |
| 
 | |
|   /* output_done_event may or may not exist.  It will exist if the tty
 | |
|      was opened by fhandler_tty_master::init, normally called at
 | |
|      startup if use_tty is non-zero.  It will not exist if this is a
 | |
|      pty opened by fhandler_pty_master::open.  In the former case, tty
 | |
|      output is handled by a separate thread which controls output.  */
 | |
|   __small_sprintf (buf, OUTPUT_DONE_EVENT, ttynum);
 | |
|   output_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);
 | |
| 
 | |
|   if (!(output_mutex = get_ttyp ()->open_output_mutex ()))
 | |
|     {
 | |
|       termios_printf ("open output mutex failed, %E");
 | |
|       __seterrno ();
 | |
|       return 0;
 | |
|     }
 | |
|   if (!(input_mutex = get_ttyp ()->open_input_mutex ()))
 | |
|     {
 | |
|       termios_printf ("open input mutex failed, %E");
 | |
|       __seterrno ();
 | |
|       return 0;
 | |
|     }
 | |
|   __small_sprintf (buf, INPUT_AVAILABLE_EVENT, ttynum);
 | |
|   if (!(input_available_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf)))
 | |
|     {
 | |
|       termios_printf ("open input event failed, %E");
 | |
|       __seterrno ();
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|   /* The ioctl events may or may not exist.  See output_done_event,
 | |
|      above.  */
 | |
|   __small_sprintf (buf, IOCTL_REQUEST_EVENT, ttynum);
 | |
|   ioctl_request_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);
 | |
|   __small_sprintf (buf, IOCTL_DONE_EVENT, ttynum);
 | |
|   ioctl_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);
 | |
| 
 | |
|   /* FIXME: Needs a method to eliminate tty races */
 | |
|   {
 | |
|     acquire_output_mutex (500);
 | |
|     inuse = get_ttyp ()->create_inuse (TTY_SLAVE_ALIVE);
 | |
|     get_ttyp ()->was_opened = TRUE;
 | |
|     release_output_mutex ();
 | |
|   }
 | |
| 
 | |
|   /* Duplicate tty handles.  */
 | |
| 
 | |
|   if (!get_ttyp ()->from_slave || !get_ttyp ()->to_slave)
 | |
|     {
 | |
|       termios_printf ("tty handles have been closed");
 | |
|       set_errno (EACCES);
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|   HANDLE from_master_local, to_master_local;
 | |
| 
 | |
|   if (!wincap.has_security () ||
 | |
|       cygserver_running!=CYGSERVER_OK ||
 | |
|       !cygserver_attach_tty ( &from_master_local, &to_master_local))
 | |
|     {
 | |
|       termios_printf ("cannot dup handles via server. using old method.");
 | |
| 
 | |
|       HANDLE tty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE,
 | |
| 				      get_ttyp ()->master_pid);
 | |
|       termios_printf ("tty own handle %p",tty_owner);
 | |
|       if (tty_owner == NULL)
 | |
| 	{
 | |
| 	  termios_printf ("can't open tty (%d) handle process %d",
 | |
| 			  ttynum, get_ttyp ()->master_pid);
 | |
| 	  __seterrno ();
 | |
| 	  return 0;
 | |
| 	}
 | |
| 
 | |
|       if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master,
 | |
| 			    hMainProc, &from_master_local, 0, TRUE,
 | |
| 			    DUPLICATE_SAME_ACCESS))
 | |
| 	{
 | |
| 	  termios_printf ("can't duplicate input, %E");
 | |
| 	  __seterrno ();
 | |
| 	  return 0;
 | |
| 	}
 | |
| 
 | |
|       if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master,
 | |
| 			  hMainProc, &to_master_local, 0, TRUE,
 | |
| 			  DUPLICATE_SAME_ACCESS))
 | |
| 	{
 | |
| 	  termios_printf ("can't duplicate output, %E");
 | |
| 	  __seterrno ();
 | |
| 	  return 0;
 | |
| 	}
 | |
|       CloseHandle (tty_owner);
 | |
|     }
 | |
| 
 | |
|   termios_printf ("duplicated from_master %p->%p from tty_owner",
 | |
|       get_ttyp ()->from_master, from_master_local);
 | |
|   termios_printf ("duplicated to_master %p->%p from tty_owner",
 | |
|       get_ttyp ()->to_master, to_master_local);
 | |
| 
 | |
|   set_io_handle (from_master_local);
 | |
|   ProtectHandle1 (from_master_local, from_pty);
 | |
|   set_output_handle (to_master_local);
 | |
|   ProtectHandle1 (to_master_local, to_pty);
 | |
| 
 | |
|   set_open_status ();
 | |
|   termios_printf ("tty%d opened", ttynum);
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_tty_slave::cygserver_attach_tty (LPHANDLE from_master_ptr,
 | |
| 					  LPHANDLE to_master_ptr)
 | |
| {
 | |
|   if (!from_master_ptr || !to_master_ptr)
 | |
|     return 0;
 | |
| 
 | |
|   client_request_attach_tty *request =
 | |
| 	new client_request_attach_tty ((DWORD) GetCurrentProcessId (),
 | |
| 				      (DWORD) get_ttyp ()->master_pid,
 | |
| 				      (HANDLE) get_ttyp ()->from_master,
 | |
| 				      (HANDLE) get_ttyp ()->to_master);
 | |
| 
 | |
|   if (cygserver_request (request) != 0 ||
 | |
| 	request->header.error_code != 0)
 | |
|     return 0;
 | |
| 
 | |
| /*
 | |
|   struct request_attach_tty req;
 | |
|   INIT_REQUEST (req, CYGSERVER_REQUEST_ATTACH_TTY);
 | |
|   req.pid = GetCurrentProcessId ();
 | |
|   req.master_pid = get_ttyp ()->master_pid;
 | |
|   req.from_master = get_ttyp ()->from_master;
 | |
|   req.to_master = get_ttyp ()->to_master;
 | |
|   if (cygserver_request ((struct request_header*) &req) != 0)
 | |
|     return 0;
 | |
| */
 | |
|   *from_master_ptr = request->from_master ();
 | |
|   *to_master_ptr = request->to_master ();
 | |
|   delete request;
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| void
 | |
| fhandler_tty_slave::init (HANDLE, DWORD a, mode_t)
 | |
| {
 | |
|   int mode = 0;
 | |
| 
 | |
|   a &= GENERIC_READ | GENERIC_WRITE;
 | |
|   if (a == GENERIC_READ)
 | |
|     mode = O_RDONLY;
 | |
|   if (a == GENERIC_WRITE)
 | |
|     mode = O_WRONLY;
 | |
|   if (a == (GENERIC_READ | GENERIC_WRITE))
 | |
|     mode = O_RDWR;
 | |
| 
 | |
|   open (0, mode);
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_tty_slave::write (const void *ptr, size_t len)
 | |
| {
 | |
|   DWORD n, towrite = len;
 | |
| 
 | |
|   termios_printf ("tty%d, write(%x, %d)", ttynum, ptr, len);
 | |
| 
 | |
|   acquire_output_mutex (INFINITE);
 | |
| 
 | |
|   while (len)
 | |
|     {
 | |
|       n = min (OUT_BUFFER_SIZE, len);
 | |
|       char *buf = (char *)ptr;
 | |
|       ptr = (char *) ptr + n;
 | |
|       len -= n;
 | |
| 
 | |
|       /* Previous write may have set write_error to != 0.  Check it here.
 | |
| 	 This is less than optimal, but the alternative slows down tty
 | |
| 	 writes enormously. */
 | |
|       if (get_ttyp ()->write_error)
 | |
| 	{
 | |
| 	  set_errno (get_ttyp ()->write_error);
 | |
| 	  towrite = (DWORD) -1;
 | |
| 	  break;
 | |
| 	}
 | |
| 
 | |
|       if (WriteFile (get_output_handle (), buf, n, &n, NULL) == FALSE)
 | |
| 	{
 | |
| 	  DWORD err = GetLastError ();
 | |
| 	  termios_printf ("WriteFile failed, %E");
 | |
| 	  switch (err)
 | |
| 	    {
 | |
| 	    case ERROR_NO_DATA:
 | |
| 	      err = ERROR_IO_DEVICE;
 | |
| 	    default:
 | |
| 	      __seterrno_from_win_error (err);
 | |
| 	    }
 | |
| 	  _raise (SIGHUP);		/* FIXME: Should this be SIGTTOU? */
 | |
| 	  towrite = (DWORD) -1;
 | |
| 	  break;
 | |
| 	}
 | |
| 
 | |
|       if (output_done_event != NULL)
 | |
| 	{
 | |
| 	  DWORD rc;
 | |
| 	  DWORD x = n * 1000;
 | |
| 	  rc = WaitForSingleObject (output_done_event, x);
 | |
| 	  termios_printf ("waited %d ms for output_done_event, WFSO %d", x, rc);
 | |
| 	}
 | |
|     }
 | |
|   release_output_mutex ();
 | |
|   return towrite;
 | |
| }
 | |
| 
 | |
| int __stdcall
 | |
| fhandler_tty_slave::read (void *ptr, size_t len)
 | |
| {
 | |
|   DWORD n;
 | |
|   int totalread = 0;
 | |
|   int vmin = INT_MAX;
 | |
|   int vtime = 0;	/* Initialized to prevent -Wuninitialized warning */
 | |
|   size_t readlen;
 | |
|   DWORD bytes_in_pipe;
 | |
|   char buf[INP_BUFFER_SIZE];
 | |
|   char peek_buf[INP_BUFFER_SIZE];
 | |
|   DWORD time_to_wait;
 | |
|   DWORD rc;
 | |
|   HANDLE w4[2];
 | |
| 
 | |
|   termios_printf ("read(%x, %d) handle %p", ptr, len, get_handle ());
 | |
| 
 | |
|   if (!(get_ttyp ()->ti.c_lflag & ICANON))
 | |
|     {
 | |
|       vmin = get_ttyp ()->ti.c_cc[VMIN];
 | |
|       if (vmin > INP_BUFFER_SIZE)
 | |
| 	vmin = INP_BUFFER_SIZE;
 | |
|       vtime = get_ttyp ()->ti.c_cc[VTIME];
 | |
|       if (vmin < 0) vmin = 0;
 | |
|       if (vtime < 0) vtime = 0;
 | |
|       if (vmin == 0)
 | |
| 	time_to_wait = INFINITE;
 | |
|       else
 | |
| 	time_to_wait = (vtime == 0 ? INFINITE : 100 * vtime);
 | |
|     }
 | |
|   else
 | |
|     time_to_wait = INFINITE;
 | |
| 
 | |
|   w4[0] = signal_arrived;
 | |
|   w4[1] = input_available_event;
 | |
| 
 | |
|   while (len)
 | |
|     {
 | |
|       rc = WaitForMultipleObjects (2, w4, FALSE, time_to_wait);
 | |
|       if (rc == WAIT_OBJECT_0)
 | |
| 	{
 | |
| 	  /* if we've received signal after successfully reading some data,
 | |
| 	     just return all data successfully read */
 | |
| 	  if (totalread > 0)
 | |
| 	    break;
 | |
| 	  set_sig_errno (EINTR);
 | |
| 	  return -1;
 | |
| 	}
 | |
|       else if (rc == WAIT_FAILED)
 | |
| 	{
 | |
| 	  termios_printf ("wait for input event failed, %E");
 | |
| 	  break;
 | |
| 	}
 | |
|       else if (rc == WAIT_TIMEOUT)
 | |
| 	break;
 | |
|       rc = WaitForSingleObject (input_mutex, 1000);
 | |
|       if (rc == WAIT_FAILED)
 | |
| 	{
 | |
| 	  termios_printf ("wait for input mutex failed, %E");
 | |
| 	  break;
 | |
| 	}
 | |
|       else if (rc == WAIT_TIMEOUT)
 | |
| 	{
 | |
| 	  termios_printf ("failed to acquire input mutex after input event arrived");
 | |
| 	  break;
 | |
| 	}
 | |
|       if (!PeekNamedPipe (get_handle (), peek_buf, sizeof(peek_buf), &bytes_in_pipe, NULL, NULL))
 | |
| 	{
 | |
| 	  termios_printf ("PeekNamedPipe failed, %E");
 | |
| 	  _raise (SIGHUP);
 | |
| 	  bytes_in_pipe = 0;
 | |
| 	}
 | |
|       readlen = min (bytes_in_pipe, min (len, sizeof (buf)));
 | |
|       if (readlen)
 | |
| 	{
 | |
| 	  termios_printf ("reading %d bytes (vtime %d)", readlen, vtime);
 | |
| 	  if (ReadFile (get_handle (), buf, readlen, &n, NULL) == FALSE)
 | |
| 	    {
 | |
| 	      termios_printf ("read failed, %E");
 | |
| 	      _raise (SIGHUP);
 | |
| 	    }
 | |
| 	  /* MSDN states that 5th prameter can be used to determine total
 | |
| 	     number of bytes in pipe, but for some reason this number doesn't
 | |
| 	     change after successful read. So we have to peek into the pipe
 | |
| 	     again to see if input is still available */
 | |
| 	  if (!PeekNamedPipe (get_handle (), peek_buf, 1, &bytes_in_pipe, NULL, NULL))
 | |
| 	    {
 | |
| 	      termios_printf ("PeekNamedPipe failed, %E");
 | |
| 	      _raise (SIGHUP);
 | |
| 	      bytes_in_pipe = 0;
 | |
| 	    }
 | |
| 	  if (n)
 | |
| 	    {
 | |
| 	      len -= n;
 | |
| 	      totalread += n;
 | |
| 	      memcpy (ptr, buf, n);
 | |
| 	      ptr = (char *) ptr + n;
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|       if (!bytes_in_pipe)
 | |
| 	ResetEvent (input_available_event);
 | |
| 
 | |
|       ReleaseMutex (input_mutex);
 | |
| 
 | |
|       if (get_ttyp ()->read_retval < 0)	// read error
 | |
| 	{
 | |
| 	  set_errno (-get_ttyp ()->read_retval);
 | |
| 	  totalread = -1;
 | |
| 	  break;
 | |
| 	}
 | |
|       if (get_ttyp ()->read_retval == 0)	//EOF
 | |
| 	{
 | |
| 	  termios_printf ("saw EOF");
 | |
| 	  break;
 | |
| 	}
 | |
|       if (get_ttyp ()->ti.c_lflag & ICANON || is_nonblocking ())
 | |
| 	break;
 | |
|       if (totalread >= vmin && (vmin > 0 || totalread > 0))
 | |
| 	break;
 | |
| 
 | |
|       /* vmin == 0 && vtime == 0:
 | |
|        *   we've already read all input, if any, so return immediately
 | |
|        * vmin == 0 && vtime > 0:
 | |
|        *   we've waited for input 10*vtime ms in WFSO(input_available_event),
 | |
|        *   no matter whether any input arrived, we shouldn't wait any longer,
 | |
|        *   so return immediately
 | |
|        * vmin > 0 && vtime == 0:
 | |
|        *   here, totalread < vmin, so continue waiting until more data
 | |
|        *   arrive
 | |
|        * vmin > 0 && vtime > 0:
 | |
|        *   similar to the previous here, totalread < vmin, and timer
 | |
|        *   hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT,
 | |
|        *   so "restart timer" and wait until more data arrive
 | |
|        */
 | |
| 
 | |
|       if (vmin == 0)
 | |
| 	break;
 | |
|     }
 | |
|   termios_printf ("%d=read(%x, %d)", totalread, ptr, len);
 | |
|   return totalread;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_tty_common::dup (fhandler_base *child)
 | |
| {
 | |
|   fhandler_tty_slave *fts = (fhandler_tty_slave *) child;
 | |
|   int errind;
 | |
| 
 | |
|   fts->ttynum = ttynum;
 | |
|   fts->tcinit (get_ttyp ());
 | |
| 
 | |
|   attach_tty (ttynum);
 | |
|   tc->set_ctty (ttynum, openflags);
 | |
| 
 | |
|   HANDLE nh;
 | |
| 
 | |
|   if (output_done_event == NULL)
 | |
|     fts->output_done_event = NULL;
 | |
|   else if (!DuplicateHandle (hMainProc, output_done_event, hMainProc,
 | |
| 			     &fts->output_done_event, 0, 1,
 | |
| 			     DUPLICATE_SAME_ACCESS))
 | |
|     {
 | |
|       errind = 1;
 | |
|       goto err;
 | |
|     }
 | |
|   if (ioctl_request_event == NULL)
 | |
|     fts->ioctl_request_event = NULL;
 | |
|   else if (!DuplicateHandle (hMainProc, ioctl_request_event, hMainProc,
 | |
| 			     &fts->ioctl_request_event, 0, 1,
 | |
| 			     DUPLICATE_SAME_ACCESS))
 | |
|     {
 | |
|       errind = 2;
 | |
|       goto err;
 | |
|     }
 | |
|   if (ioctl_done_event == NULL)
 | |
|     fts->ioctl_done_event = NULL;
 | |
|   else if (!DuplicateHandle (hMainProc, ioctl_done_event, hMainProc,
 | |
| 			     &fts->ioctl_done_event, 0, 1,
 | |
| 			     DUPLICATE_SAME_ACCESS))
 | |
|     {
 | |
|       errind = 3;
 | |
|       goto err;
 | |
|     }
 | |
|   if (!DuplicateHandle (hMainProc, input_available_event, hMainProc,
 | |
| 			&fts->input_available_event, 0, 1,
 | |
| 			DUPLICATE_SAME_ACCESS))
 | |
|     {
 | |
|       errind = 4;
 | |
|       goto err;
 | |
|     }
 | |
|   if (!DuplicateHandle (hMainProc, output_mutex, hMainProc,
 | |
| 			&fts->output_mutex, 0, 1,
 | |
| 			DUPLICATE_SAME_ACCESS))
 | |
|     {
 | |
|       errind = 5;
 | |
|       goto err;
 | |
|     }
 | |
|   if (!DuplicateHandle (hMainProc, input_mutex, hMainProc,
 | |
| 			&fts->input_mutex, 0, 1,
 | |
| 			DUPLICATE_SAME_ACCESS))
 | |
|     {
 | |
|       errind = 6;
 | |
|       goto err;
 | |
|     }
 | |
|   if (!DuplicateHandle (hMainProc, get_handle (), hMainProc,
 | |
| 			&nh, 0, 1,
 | |
| 			DUPLICATE_SAME_ACCESS))
 | |
|     {
 | |
|       errind = 7;
 | |
|       goto err;
 | |
|     }
 | |
|   fts->set_io_handle (nh);
 | |
| 
 | |
|   if (!DuplicateHandle (hMainProc, get_output_handle (), hMainProc,
 | |
| 			&nh, 0, 1,
 | |
| 			DUPLICATE_SAME_ACCESS))
 | |
|     {
 | |
|       errind = 8;
 | |
|       goto err;
 | |
|     }
 | |
|   fts->set_output_handle (nh);
 | |
| 
 | |
|   if (inuse == NULL)
 | |
|     fts->inuse = NULL;
 | |
|   else if (!DuplicateHandle (hMainProc, inuse, hMainProc,
 | |
| 			     &fts->inuse, 0, 1,
 | |
| 			     DUPLICATE_SAME_ACCESS))
 | |
|     {
 | |
|       errind = 9;
 | |
|       goto err;
 | |
|     }
 | |
|   return 0;
 | |
| 
 | |
| err:
 | |
|   __seterrno ();
 | |
|   termios_printf ("dup %d failed in DuplicateHandle, %E", errind);
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_tty_slave::tcgetattr (struct termios *t)
 | |
| {
 | |
|   *t = get_ttyp ()->ti;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_tty_slave::tcsetattr (int, const struct termios *t)
 | |
| {
 | |
|   acquire_output_mutex (INFINITE);
 | |
|   get_ttyp ()->ti = *t;
 | |
|   release_output_mutex ();
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_tty_slave::tcflush (int)
 | |
| {
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_tty_slave::ioctl (unsigned int cmd, void *arg)
 | |
| {
 | |
|   termios_printf ("ioctl (%x)", cmd);
 | |
| 
 | |
|   if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid &&
 | |
| 	 myself->ctty == ttynum && (get_ttyp ()->ti.c_lflag & TOSTOP))
 | |
|     {
 | |
|       /* background process */
 | |
|       termios_printf ("bg ioctl pgid %d, tpgid %d, ctty %d",
 | |
| 		      myself->pgid, get_ttyp ()->getpgid (), myself->ctty);
 | |
|       _raise (SIGTTOU);
 | |
|     }
 | |
| 
 | |
|   switch (cmd)
 | |
|     {
 | |
|     case TIOCGWINSZ:
 | |
|     case TIOCSWINSZ:
 | |
|       break;
 | |
|     case FIONBIO:
 | |
|       set_nonblocking (*(int *) arg);
 | |
|       goto out;
 | |
|     default:
 | |
|       set_errno (EINVAL);
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|   acquire_output_mutex (INFINITE);
 | |
| 
 | |
|   get_ttyp ()->cmd = cmd;
 | |
|   get_ttyp ()->ioctl_retval = 0;
 | |
|   switch (cmd)
 | |
|     {
 | |
|     case TIOCGWINSZ:
 | |
|       get_ttyp ()->arg.winsize = get_ttyp ()->winsize;
 | |
|       if (ioctl_request_event)
 | |
| 	SetEvent (ioctl_request_event);
 | |
|       * (struct winsize *) arg = get_ttyp ()->arg.winsize;
 | |
|       if (ioctl_done_event)
 | |
| 	WaitForSingleObject (ioctl_done_event, INFINITE);
 | |
|       get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
 | |
|       break;
 | |
|     case TIOCSWINSZ:
 | |
|       get_ttyp ()->ioctl_retval = -1;
 | |
|       get_ttyp ()->arg.winsize = * (struct winsize *) arg;
 | |
|       if (ioctl_request_event)
 | |
| 	SetEvent (ioctl_request_event);
 | |
|       if (ioctl_done_event)
 | |
| 	WaitForSingleObject (ioctl_done_event, INFINITE);
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|   release_output_mutex ();
 | |
| 
 | |
| out:
 | |
|   termios_printf ("%d = ioctl (%x)", get_ttyp ()->ioctl_retval, cmd);
 | |
|   return get_ttyp ()->ioctl_retval;
 | |
| }
 | |
| 
 | |
| /*******************************************************
 | |
|  fhandler_pty_master
 | |
| */
 | |
| fhandler_pty_master::fhandler_pty_master (DWORD devtype, int unit)
 | |
|   : fhandler_tty_common (devtype, unit)
 | |
| {
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_pty_master::open (path_conv *, int flags, mode_t)
 | |
| {
 | |
|   ttynum = cygwin_shared->tty.allocate_tty (0);
 | |
|   if (ttynum < 0)
 | |
|     return 0;
 | |
| 
 | |
|   cygwin_shared->tty[ttynum]->common_init (this);
 | |
|   inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE);
 | |
|   set_flags ((flags & ~O_TEXT) | O_BINARY);
 | |
|   set_open_status ();
 | |
| 
 | |
|   termios_printf ("opened pty master tty%d<%p>", ttynum, this);
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_tty_common::close ()
 | |
| {
 | |
|   if (output_done_event && !CloseHandle (output_done_event))
 | |
|     termios_printf ("CloseHandle (output_done_event), %E");
 | |
|   if (ioctl_done_event && !CloseHandle (ioctl_done_event))
 | |
|     termios_printf ("CloseHandle (ioctl_done_event), %E");
 | |
|   if (ioctl_request_event && !CloseHandle (ioctl_request_event))
 | |
|     termios_printf ("CloseHandle (ioctl_request_event), %E");
 | |
|   if (inuse && !CloseHandle (inuse))
 | |
|     termios_printf ("CloseHandle (inuse), %E");
 | |
|   if (!ForceCloseHandle (input_mutex))
 | |
|     termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex);
 | |
|   if (!ForceCloseHandle (output_mutex))
 | |
|     termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
 | |
| 
 | |
|   /* Send EOF to slaves if master side is closed */
 | |
|   if (!get_ttyp ()->master_alive ())
 | |
|     {
 | |
|       termios_printf ("no more masters left. sending EOF" );
 | |
|       SetEvent (input_available_event);
 | |
|     }
 | |
| 
 | |
|   if (!ForceCloseHandle (input_available_event))
 | |
|     termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event);
 | |
|   if (!ForceCloseHandle1 (get_handle (), from_pty))
 | |
|     termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ());
 | |
|   if (!ForceCloseHandle1 (get_output_handle (), to_pty))
 | |
|     termios_printf ("CloseHandle (get_output_handle ()<%p>), %E", get_output_handle ());
 | |
| 
 | |
|   inuse = NULL;
 | |
|   termios_printf ("tty%d <%p,%p> closed", ttynum, get_handle (), get_output_handle ());
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_pty_master::close ()
 | |
| {
 | |
| #if 0
 | |
|   while (accept_input () > 0)
 | |
|     continue;
 | |
| #endif
 | |
|   this->fhandler_tty_common::close ();
 | |
| 
 | |
|   if (!get_ttyp ()->master_alive ())
 | |
|     {
 | |
|       termios_printf ("freeing tty%d (%d)", ttynum, get_ttyp ()->ntty);
 | |
| #if 0
 | |
|       if (get_ttyp ()->to_slave)
 | |
| 	ForceCloseHandle1 (get_ttyp ()->to_slave, to_slave);
 | |
|       if (get_ttyp ()->from_slave)
 | |
| 	ForceCloseHandle1 (get_ttyp ()->from_slave, from_slave);
 | |
| #endif
 | |
|       if (get_ttyp ()->from_master)
 | |
| 	CloseHandle (get_ttyp ()->from_master);
 | |
|       if (get_ttyp ()->to_master)
 | |
| 	CloseHandle (get_ttyp ()->to_master);
 | |
|       get_ttyp ()->init ();
 | |
|     }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_pty_master::write (const void *ptr, size_t len)
 | |
| {
 | |
|   (void) line_edit ((char *) ptr, len);
 | |
|   return len;
 | |
| }
 | |
| 
 | |
| int __stdcall
 | |
| fhandler_pty_master::read (void *ptr, size_t len)
 | |
| {
 | |
|   return process_slave_output ((char *) ptr, len, pktmode);
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_pty_master::tcgetattr (struct termios *t)
 | |
| {
 | |
|   *t = cygwin_shared->tty[ttynum]->ti;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_pty_master::tcsetattr (int, const struct termios *t)
 | |
| {
 | |
|   cygwin_shared->tty[ttynum]->ti = *t;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_pty_master::tcflush (int)
 | |
| {
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
 | |
| {
 | |
|   switch (cmd)
 | |
|     {
 | |
|       case TIOCPKT:
 | |
| 	pktmode = * (int *) arg;
 | |
| 	break;
 | |
|       case TIOCGWINSZ:
 | |
| 	* (struct winsize *) arg = get_ttyp ()->winsize;
 | |
| 	break;
 | |
|       case TIOCSWINSZ:
 | |
| 	get_ttyp ()->winsize = * (struct winsize *) arg;
 | |
| 	_kill (-get_ttyp ()->getpgid (), SIGWINCH);
 | |
| 	break;
 | |
|       case FIONBIO:
 | |
| 	set_nonblocking (*(int *) arg);
 | |
| 	break;
 | |
|       default:
 | |
| 	set_errno (EINVAL);
 | |
| 	return -1;
 | |
|     }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| char *
 | |
| fhandler_pty_master::ptsname (void)
 | |
| {
 | |
|   static char buf[32];
 | |
| 
 | |
|   __small_sprintf (buf, "/dev/tty%d", ttynum);
 | |
|   return buf;
 | |
| }
 | |
| 
 | |
| void
 | |
| fhandler_tty_common::set_close_on_exec (int val)
 | |
| {
 | |
| #ifndef DEBUGGING
 | |
|   this->fhandler_base::set_close_on_exec (val);
 | |
| #else
 | |
|   /* FIXME: This is a duplication from fhandler_base::set_close_on_exec.
 | |
|      It is here because we need to specify the "from_pty" stuff here or
 | |
|      we'll get warnings from ForceCloseHandle when debugging. */
 | |
|   set_inheritance (get_io_handle (), val);
 | |
|   set_close_on_exec_flag (val);
 | |
| #endif
 | |
|   if (output_done_event)
 | |
|     set_inheritance (output_done_event, val);
 | |
|   if (ioctl_request_event)
 | |
|     set_inheritance (ioctl_request_event, val);
 | |
|   if (ioctl_done_event)
 | |
|     set_inheritance (ioctl_done_event, val);
 | |
|   if (inuse)
 | |
|     set_inheritance (inuse, val);
 | |
|   set_inheritance (output_mutex, val);
 | |
|   set_inheritance (input_mutex, val);
 | |
|   set_inheritance (input_available_event, val);
 | |
|   set_inheritance (output_handle, val);
 | |
| }
 | |
| 
 | |
| void
 | |
| fhandler_tty_common::fixup_after_fork (HANDLE parent)
 | |
| {
 | |
|   this->fhandler_termios::fixup_after_fork (parent);
 | |
|   if (output_done_event)
 | |
|     fork_fixup (parent, output_done_event, "output_done_event");
 | |
|   if (ioctl_request_event)
 | |
|     fork_fixup (parent, ioctl_request_event, "ioctl_request_event");
 | |
|   if (ioctl_done_event)
 | |
|     fork_fixup (parent, ioctl_done_event, "ioctl_done_event");
 | |
|   if (output_mutex)
 | |
|     fork_fixup (parent, output_mutex, "output_mutex");
 | |
|   if (input_mutex)
 | |
|     fork_fixup (parent, input_mutex, "input_mutex");
 | |
|   if (input_available_event)
 | |
|     fork_fixup (parent, input_available_event, "input_available_event");
 | |
|   fork_fixup (parent, inuse, "inuse");
 | |
| }
 | |
| 
 | |
| void
 | |
| fhandler_pty_master::set_close_on_exec (int val)
 | |
| {
 | |
|   this->fhandler_tty_common::set_close_on_exec (val);
 | |
| 
 | |
|   /* FIXME: There is a console handle leak here. */
 | |
|   if (get_ttyp ()->master_pid == GetCurrentProcessId ())
 | |
|     {
 | |
|       get_ttyp ()->from_slave = get_handle ();
 | |
|       get_ttyp ()->to_slave = get_output_handle ();
 | |
|       termios_printf ("from_slave %p, to_slave %p", get_handle (),
 | |
| 		      get_output_handle ());
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| fhandler_tty_master::fixup_after_fork (HANDLE child)
 | |
| {
 | |
|   this->fhandler_pty_master::fixup_after_fork (child);
 | |
|   console->fixup_after_fork (child);
 | |
| }
 | |
| 
 | |
| void
 | |
| fhandler_tty_master::fixup_after_exec (HANDLE)
 | |
| {
 | |
|   console->close ();
 | |
|   init_console ();
 | |
|   return;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_tty_master::init_console ()
 | |
| {
 | |
|   console = (fhandler_console *) cygheap->fdtab.build_fhandler (-1, FH_CONSOLE, "/dev/ttym");
 | |
|   if (console == NULL)
 | |
|     return -1;
 | |
| 
 | |
|   console->init (INVALID_HANDLE_VALUE, GENERIC_READ | GENERIC_WRITE, O_BINARY);
 | |
|   console->set_r_no_interrupt (1);
 | |
|   return 0;
 | |
| }
 |