282 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			282 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* tty.cc
 | |
| 
 | |
| 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 "miscfuncs.h"
 | |
| #include <unistd.h>
 | |
| #include <utmp.h>
 | |
| #include <sys/cygwin.h>
 | |
| #include "cygerrno.h"
 | |
| #include "security.h"
 | |
| #include "path.h"
 | |
| #include "fhandler.h"
 | |
| #include "dtable.h"
 | |
| #include "cygheap.h"
 | |
| #include "pinfo.h"
 | |
| #include "shared_info.h"
 | |
| 
 | |
| HANDLE NO_COPY tty_list::mutex = NULL;
 | |
| 
 | |
| extern "C" int
 | |
| getpt (void)
 | |
| {
 | |
|   return open ("/dev/ptmx", O_RDWR | O_NOCTTY);
 | |
| }
 | |
| 
 | |
| extern "C" int
 | |
| posix_openpt (int oflags)
 | |
| {
 | |
|   return open ("/dev/ptmx", oflags);
 | |
| }
 | |
| 
 | |
| extern "C" int
 | |
| grantpt (int fd)
 | |
| {
 | |
|   cygheap_fdget cfd (fd);
 | |
|   return cfd < 0 ? -1 : 0;
 | |
| }
 | |
| 
 | |
| extern "C" int
 | |
| unlockpt (int fd)
 | |
| {
 | |
|   cygheap_fdget cfd (fd);
 | |
|   return cfd < 0 ? -1 : 0;
 | |
| }
 | |
| 
 | |
| extern "C" int
 | |
| revoke (char *ttyname)
 | |
| {
 | |
|   set_errno (ENOSYS);
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| extern "C" int
 | |
| ttyslot (void)
 | |
| {
 | |
|   if (myself->ctty <= 0 || iscons_dev (myself->ctty))
 | |
|     return -1;
 | |
|   return device::minor (myself->ctty);
 | |
| }
 | |
| 
 | |
| void __stdcall
 | |
| tty_list::init_session ()
 | |
| {
 | |
|   char mutex_name[MAX_PATH];
 | |
|   char *name = shared_name (mutex_name, "tty_list::mutex", 0);
 | |
| 
 | |
|   /* tty_list::mutex is used while searching for a tty slot */
 | |
|   if (!(mutex = CreateMutex (&sec_all_nih, FALSE, name)))
 | |
|     api_fatal ("can't create tty_list::mutex '%s', %E", name);
 | |
|   ProtectHandle (mutex);
 | |
| }
 | |
| 
 | |
| void __stdcall
 | |
| tty::init_session ()
 | |
| {
 | |
|   if (!myself->cygstarted && NOTSTATE (myself, PID_CYGPARENT))
 | |
|     cygheap->fdtab.get_debugger_info ();
 | |
| }
 | |
| 
 | |
| int __reg2
 | |
| tty_list::attach (int n)
 | |
| {
 | |
|   int res;
 | |
|   if (iscons_dev (n))
 | |
|     res = -1;
 | |
|   else if (n != -1)
 | |
|     res = connect (device::minor (n));
 | |
|   else
 | |
|     res = -1;
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| int
 | |
| tty_list::connect (int ttynum)
 | |
| {
 | |
|   if (ttynum < 0 || ttynum >= NTTYS)
 | |
|     {
 | |
|       termios_printf ("ttynum (%d) out of range", ttynum);
 | |
|       return -1;
 | |
|     }
 | |
|   if (!ttys[ttynum].exists ())
 | |
|     {
 | |
|       termios_printf ("pty %d was not allocated", ttynum);
 | |
|       set_errno (ENXIO);
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|   return ttynum;
 | |
| }
 | |
| 
 | |
| void
 | |
| tty_list::init ()
 | |
| {
 | |
|   for (int i = 0; i < NTTYS; i++)
 | |
|     {
 | |
|       ttys[i].init ();
 | |
|       ttys[i].setntty (DEV_PTYS_MAJOR, i);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Search for a free tty and allocate it.
 | |
|    Return tty number or -1 if error.
 | |
|  */
 | |
| int
 | |
| tty_list::allocate (HANDLE& r, HANDLE& w)
 | |
| {
 | |
|   lock_ttys here;
 | |
|   int freetty = -1;
 | |
| 
 | |
|   tty *t = NULL;
 | |
|   for (int i = 0; i < NTTYS; i++)
 | |
|     if (ttys[i].not_allocated (r, w))
 | |
|       {
 | |
| 	t = ttys + i;
 | |
| 	t->init ();
 | |
| 	t->setsid (0);
 | |
| 	freetty = i;
 | |
| 	break;
 | |
|       }
 | |
| 
 | |
|   if (freetty >= 0)
 | |
|     termios_printf ("pty%d allocated", freetty);
 | |
|   else
 | |
|     {
 | |
|       system_printf ("No pty allocated");
 | |
|       r = w = NULL;
 | |
|     }
 | |
| 
 | |
|   return freetty;
 | |
| }
 | |
| 
 | |
| bool
 | |
| tty::not_allocated (HANDLE& r, HANDLE& w)
 | |
| {
 | |
|   /* Attempt to open the from-master side of the tty.  If it is accessible
 | |
|      then it exists although we may not have privileges to actually use it. */
 | |
|   char pipename[sizeof("ptyNNNN-from-master")];
 | |
|   __small_sprintf (pipename, "pty%d-from-master", get_minor ());
 | |
|   /* fhandler_pipe::create returns 0 when creation succeeds */
 | |
|   return fhandler_pipe::create (&sec_none, &r, &w,
 | |
| 				fhandler_pty_common::pipesize, pipename,
 | |
| 				0) == 0;
 | |
| }
 | |
| 
 | |
| bool
 | |
| tty::exists ()
 | |
| {
 | |
|   HANDLE r, w;
 | |
|   bool res;
 | |
|   if (!not_allocated (r, w))
 | |
|     res = true;
 | |
| 
 | |
|   else
 | |
|     {
 | |
|       /* Handles are left open when not_allocated finds a non-open "tty" */
 | |
|       CloseHandle (r);
 | |
|       CloseHandle (w);
 | |
|       res = false;
 | |
|     }
 | |
|   debug_printf ("exists %d", res);
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| bool
 | |
| tty::slave_alive ()
 | |
| {
 | |
|   HANDLE ev;
 | |
|   if ((ev = open_inuse (READ_CONTROL)))
 | |
|     CloseHandle (ev);
 | |
|   return ev != NULL;
 | |
| }
 | |
| 
 | |
| HANDLE
 | |
| tty::open_mutex (const char *mutex, ACCESS_MASK access)
 | |
| {
 | |
|   char buf[MAX_PATH];
 | |
|   shared_name (buf, mutex, get_minor ());
 | |
|   return OpenMutex (access, TRUE, buf);
 | |
| }
 | |
| 
 | |
| HANDLE
 | |
| tty::open_inuse (ACCESS_MASK access)
 | |
| {
 | |
|   char buf[MAX_PATH];
 | |
|   shared_name (buf, TTY_SLAVE_ALIVE, get_minor ());
 | |
|   return OpenEvent (access, FALSE, buf);
 | |
| }
 | |
| 
 | |
| HANDLE
 | |
| tty::create_inuse (PSECURITY_ATTRIBUTES sa)
 | |
| {
 | |
|   HANDLE h;
 | |
|   char buf[MAX_PATH];
 | |
| 
 | |
|   shared_name (buf, TTY_SLAVE_ALIVE, get_minor ());
 | |
|   h = CreateEvent (sa, TRUE, FALSE, buf);
 | |
|   termios_printf ("%s %p", buf, h);
 | |
|   if (!h)
 | |
|     termios_printf ("couldn't open inuse event %s, %E", buf);
 | |
|   return h;
 | |
| }
 | |
| 
 | |
| void
 | |
| tty::init ()
 | |
| {
 | |
|   output_stopped = 0;
 | |
|   setsid (0);
 | |
|   pgid = 0;
 | |
|   was_opened = false;
 | |
|   master_pid = 0;
 | |
|   is_console = false;
 | |
|   column = 0;
 | |
| }
 | |
| 
 | |
| HANDLE
 | |
| tty::get_event (const char *fmt, PSECURITY_ATTRIBUTES sa, BOOL manual_reset)
 | |
| {
 | |
|   HANDLE hev;
 | |
|   char buf[MAX_PATH];
 | |
| 
 | |
|   shared_name (buf, fmt, get_minor ());
 | |
|   if (!sa)
 | |
|     sa = &sec_all;
 | |
|   if (!(hev = CreateEvent (sa, manual_reset, FALSE, buf)))
 | |
|     {
 | |
|       termios_printf ("couldn't create %s", buf);
 | |
|       set_errno (ENOENT);	/* FIXME this can't be the right errno */
 | |
|       return NULL;
 | |
|     }
 | |
| 
 | |
|   termios_printf ("created event %s", buf);
 | |
|   return hev;
 | |
| }
 | |
| 
 | |
| lock_ttys::lock_ttys (DWORD howlong): release_me (true)
 | |
| {
 | |
|   if (WaitForSingleObject (tty_list::mutex, howlong) == WAIT_FAILED)
 | |
|     {
 | |
|       termios_printf ("WFSO for mutex %p failed, %E", tty_list::mutex);
 | |
|       release_me = false;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| lock_ttys::release ()
 | |
| {
 | |
|   ReleaseMutex (tty_list::mutex);
 | |
| }
 | |
| 
 | |
| const char *
 | |
| tty_min::ttyname ()
 | |
| {
 | |
|   device d;
 | |
|   d.parse (ntty);
 | |
|   return d.name ();
 | |
| }
 |