306c4b6737
syncronize input on master tty with slave tty. * fhandler_tty.cc (fhandler_pty_master::accept_input): Use them to syncronize with slave. * fhandler_tty.cc (fhandler_tty_slave::read): Use input mutex and event to syncronize with master. Do not limit amount of data read from master to vmin value. Interrupt on signal and return already read data, if any. * fhandler_tty.cc (fhandler_tty_slave::open): Handle input mutex and event. * fhandler_tty.cc (fhandler_tty_common::close): Ditto. * fhandler_tty.cc (fhandler_tty_common::set_close_on_exec): Ditto. * fhandler_tty.cc (fhandler_tty_common::fixup_after_fork): Ditto. * fhandler_tty.cc (fhandler_tty_common::dup): Ditto. * tty.h (tty::open_input_mutex): New function. * tty.cc (tty::common_init): Create input mutex and event.
439 lines
9.4 KiB
C++
439 lines
9.4 KiB
C++
/* tty.cc
|
|
|
|
Copyright 1997, 1998, 2000 Cygnus Solutions.
|
|
|
|
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 <errno.h>
|
|
#include <unistd.h>
|
|
#include <utmp.h>
|
|
#include <wingdi.h>
|
|
#include <winuser.h>
|
|
#include <sys/cygwin.h>
|
|
#include "cygerrno.h"
|
|
#include "fhandler.h"
|
|
#include "dtable.h"
|
|
#include "sync.h"
|
|
#include "sigproc.h"
|
|
#include "pinfo.h"
|
|
#include "shared_info.h"
|
|
#include "security.h"
|
|
|
|
extern fhandler_tty_master *tty_master;
|
|
|
|
extern "C"
|
|
int
|
|
grantpt (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
extern "C"
|
|
int
|
|
unlockpt (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
extern "C"
|
|
int
|
|
ttyslot (void)
|
|
{
|
|
if (NOTSTATE (myself, PID_USETTY))
|
|
return -1;
|
|
return myself->ctty;
|
|
}
|
|
|
|
void __stdcall
|
|
tty_init (void)
|
|
{
|
|
if (NOTSTATE (myself, PID_USETTY))
|
|
return;
|
|
if (myself->ctty == -1)
|
|
if (NOTSTATE (myself, PID_CYGPARENT))
|
|
myself->ctty = attach_tty (myself->ctty);
|
|
else
|
|
return;
|
|
if (myself->ctty == -1)
|
|
termios_printf ("Can't attach to tty");
|
|
}
|
|
|
|
/* Create session's master tty */
|
|
|
|
void __stdcall
|
|
create_tty_master (int ttynum)
|
|
{
|
|
tty_master = (fhandler_tty_master *) fdtab.build_fhandler (-1, FH_TTYM,
|
|
"/dev/ttym", ttynum);
|
|
if (tty_master->init (ttynum))
|
|
api_fatal ("Can't create master tty");
|
|
else
|
|
{
|
|
/* Log utmp entry */
|
|
struct utmp our_utmp;
|
|
|
|
bzero ((char *) &our_utmp, sizeof (utmp));
|
|
(void) time (&our_utmp.ut_time);
|
|
strncpy (our_utmp.ut_name, getlogin (), sizeof (our_utmp.ut_name));
|
|
cygwin_gethostname (our_utmp.ut_host, sizeof (our_utmp.ut_host));
|
|
__small_sprintf (our_utmp.ut_line, "tty%d", ttynum);
|
|
our_utmp.ut_type = USER_PROCESS;
|
|
myself->ctty = ttynum;
|
|
login (&our_utmp);
|
|
}
|
|
}
|
|
|
|
void __stdcall
|
|
tty_terminate (void)
|
|
{
|
|
if (NOTSTATE (myself, PID_USETTY))
|
|
return;
|
|
cygwin_shared->tty.terminate ();
|
|
}
|
|
|
|
int __stdcall
|
|
attach_tty (int num)
|
|
{
|
|
if (num != -1)
|
|
{
|
|
return cygwin_shared->tty.connect_tty (num);
|
|
}
|
|
if (NOTSTATE (myself, PID_USETTY))
|
|
return -1;
|
|
return cygwin_shared->tty.allocate_tty (1);
|
|
}
|
|
|
|
void
|
|
tty_list::terminate (void)
|
|
{
|
|
int ttynum = myself->ctty;
|
|
|
|
/* Keep master running till there are connected clients */
|
|
if (ttynum != -1 && ttys[ttynum].master_pid == GetCurrentProcessId ())
|
|
{
|
|
tty *t = ttys + ttynum;
|
|
CloseHandle (t->from_master);
|
|
CloseHandle (t->to_master);
|
|
/* Wait for children which rely on tty handling in this process to
|
|
go away */
|
|
for (int i = 0; ; i++)
|
|
{
|
|
if (!t->slave_alive ())
|
|
break;
|
|
if (i >= 100)
|
|
{
|
|
small_printf ("waiting for children using tty%d to terminate\n",
|
|
ttynum);
|
|
i = 0;
|
|
}
|
|
|
|
Sleep (200);
|
|
}
|
|
|
|
termios_printf ("tty %d master about to finish", ttynum);
|
|
ForceCloseHandle1 (t->to_slave, to_pty);
|
|
ForceCloseHandle1 (t->from_slave, from_pty);
|
|
WaitForSingleObject (tty_master->hThread, INFINITE);
|
|
t->init ();
|
|
|
|
char buf[20];
|
|
__small_sprintf (buf, "tty%d", ttynum);
|
|
logout (buf);
|
|
}
|
|
}
|
|
|
|
int
|
|
tty_list::connect_tty (int ttynum)
|
|
{
|
|
if (ttynum < 0 || ttynum >= NTTYS)
|
|
{
|
|
termios_printf ("ttynum (%d) out of range", ttynum);
|
|
return -1;
|
|
}
|
|
if (!ttys[ttynum].exists ())
|
|
{
|
|
termios_printf ("tty %d was not allocated", ttynum);
|
|
return -1;
|
|
}
|
|
|
|
return ttynum;
|
|
}
|
|
|
|
void
|
|
tty_list::init (void)
|
|
{
|
|
for (int i = 0; i < NTTYS; i++)
|
|
{
|
|
ttys[i].init ();
|
|
ttys[i].setntty (i);
|
|
}
|
|
}
|
|
|
|
/* Search for tty class for our console. Allocate new tty if our process is
|
|
the only cygwin process in the current console.
|
|
Return tty number or -1 if error.
|
|
If flag == 0, just find a free tty.
|
|
*/
|
|
int
|
|
tty_list::allocate_tty (int with_console)
|
|
{
|
|
HWND console;
|
|
|
|
/* FIXME: This whole function needs a protective mutex. */
|
|
|
|
if (!with_console)
|
|
console = NULL;
|
|
else
|
|
{
|
|
char *oldtitle = new char [TITLESIZE];
|
|
|
|
if (!oldtitle)
|
|
{
|
|
termios_printf ("Can't *allocate console title buffer");
|
|
return -1;
|
|
}
|
|
if (!GetConsoleTitle (oldtitle, TITLESIZE))
|
|
{
|
|
termios_printf ("Can't read console title");
|
|
return -1;
|
|
}
|
|
|
|
if (WaitForSingleObject (title_mutex, INFINITE) == WAIT_FAILED)
|
|
termios_printf ("WFSO for title_mutext %p failed, %E", title_mutex);
|
|
|
|
char buf[40];
|
|
|
|
__small_sprintf (buf, "cygwin.find.console.%d", myself->pid);
|
|
SetConsoleTitle (buf);
|
|
Sleep (40);
|
|
console = FindWindow (NULL, buf);
|
|
SetConsoleTitle (oldtitle);
|
|
Sleep (40);
|
|
ReleaseMutex (title_mutex);
|
|
if (console == NULL)
|
|
{
|
|
termios_printf ("Can't find console window");
|
|
return -1;
|
|
}
|
|
}
|
|
/* Is a tty allocated for console? */
|
|
|
|
int freetty = -1;
|
|
for (int i = 0; i < NTTYS; i++)
|
|
{
|
|
if (!ttys[i].exists ())
|
|
{
|
|
if (freetty < 0) /* Scanning? */
|
|
freetty = i; /* Yes. */
|
|
if (!with_console) /* Do we want to attach this to a console? */
|
|
break; /* No. We've got one. */
|
|
}
|
|
|
|
if (with_console && ttys[i].gethwnd () == console)
|
|
{
|
|
termios_printf ("console %x already associated with tty%d",
|
|
console, i);
|
|
/* Is the master alive? */
|
|
HANDLE hMaster;
|
|
hMaster = OpenProcess (PROCESS_DUP_HANDLE, FALSE, ttys[i].master_pid);
|
|
if (hMaster)
|
|
{
|
|
CloseHandle (hMaster);
|
|
return i;
|
|
}
|
|
/* Master is dead */
|
|
freetty = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* There is no tty allocated to console, allocate the first free found */
|
|
if (freetty == -1)
|
|
{
|
|
system_printf ("No free ttys available");
|
|
return -1;
|
|
}
|
|
tty *t = ttys + freetty;
|
|
t->init ();
|
|
t->setsid (-1);
|
|
t->setpgid (myself->pgid);
|
|
t->sethwnd (console);
|
|
|
|
if (with_console)
|
|
{
|
|
termios_printf ("console %x associated with tty%d", console, freetty);
|
|
create_tty_master (freetty);
|
|
}
|
|
else
|
|
termios_printf ("tty%d allocated", freetty);
|
|
return freetty;
|
|
}
|
|
|
|
BOOL
|
|
tty::slave_alive ()
|
|
{
|
|
return alive (TTY_SLAVE_ALIVE);
|
|
}
|
|
|
|
BOOL
|
|
tty::master_alive ()
|
|
{
|
|
return alive (TTY_MASTER_ALIVE);
|
|
}
|
|
|
|
BOOL
|
|
tty::alive (const char *fmt)
|
|
{
|
|
HANDLE ev;
|
|
char buf[sizeof (TTY_MASTER_ALIVE) + 16];
|
|
|
|
__small_sprintf (buf, fmt, ntty);
|
|
if ((ev = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf)))
|
|
CloseHandle (ev);
|
|
return ev != NULL;
|
|
}
|
|
|
|
HANDLE
|
|
tty::create_inuse (const char *fmt)
|
|
{
|
|
HANDLE h;
|
|
char buf[sizeof (TTY_MASTER_ALIVE) + 16];
|
|
|
|
__small_sprintf (buf, fmt, ntty);
|
|
h = CreateEvent (&sec_all, TRUE, FALSE, buf);
|
|
termios_printf ("%s = %p", buf, h);
|
|
if (!h)
|
|
termios_printf ("couldn't open inuse event, %E", buf);
|
|
return h;
|
|
}
|
|
|
|
void
|
|
tty::init (void)
|
|
{
|
|
OutputStopped = 0;
|
|
setsid (0);
|
|
pgid = 0;
|
|
hwnd = NULL;
|
|
to_slave = NULL;
|
|
from_slave = NULL;
|
|
was_opened = 0;
|
|
}
|
|
|
|
HANDLE
|
|
tty::get_event (const char *fmt, BOOL inherit)
|
|
{
|
|
HANDLE hev;
|
|
char buf[40];
|
|
|
|
__small_sprintf (buf, fmt, ntty);
|
|
if (!(hev = CreateEvent (inherit ? &sec_all : &sec_all_nih, FALSE, 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;
|
|
}
|
|
|
|
int
|
|
tty::make_pipes (fhandler_pty_master *ptym)
|
|
{
|
|
/* Create communication pipes */
|
|
|
|
/* FIXME: should this be sec_none_nih? */
|
|
if (CreatePipe (&from_master, &to_slave, &sec_all, 0) == FALSE)
|
|
{
|
|
termios_printf ("can't create input pipe");
|
|
set_errno (ENOENT);
|
|
return FALSE;
|
|
}
|
|
|
|
ProtectHandle1 (to_slave, to_pty);
|
|
if (CreatePipe (&from_slave, &to_master, &sec_all, 0) == FALSE)
|
|
{
|
|
termios_printf ("can't create output pipe");
|
|
set_errno (ENOENT);
|
|
return FALSE;
|
|
}
|
|
ProtectHandle1 (from_slave, from_pty);
|
|
termios_printf ("tty%d from_slave %p, to_slave %p", ntty, from_slave,
|
|
to_slave);
|
|
ptym->set_io_handle (from_slave);
|
|
ptym->set_output_handle (to_slave);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
tty::common_init (fhandler_pty_master *ptym)
|
|
{
|
|
/* Set termios information. Force initialization. */
|
|
ptym->tcinit (this, TRUE);
|
|
|
|
if (!make_pipes (ptym))
|
|
return FALSE;
|
|
ptym->need_nl = 0;
|
|
|
|
/* Save our pid */
|
|
|
|
master_pid = GetCurrentProcessId ();
|
|
|
|
/* Allow the others to open us (for handle duplication) */
|
|
|
|
if ((os_being_run == winNT) &&
|
|
(SetKernelObjectSecurity (hMainProc, DACL_SECURITY_INFORMATION,
|
|
get_null_sd ()) == FALSE))
|
|
small_printf ("Can't set process security, %E");
|
|
|
|
/* Create synchronisation events */
|
|
|
|
if (ptym->get_device () != FH_TTYM)
|
|
{
|
|
ptym->output_done_event = ptym->ioctl_done_event =
|
|
ptym->ioctl_request_event = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (!(ptym->output_done_event = get_event (OUTPUT_DONE_EVENT, FALSE)))
|
|
return FALSE;
|
|
if (!(ptym->ioctl_done_event = get_event (IOCTL_DONE_EVENT, FALSE)))
|
|
return FALSE;
|
|
if (!(ptym->ioctl_request_event = get_event (IOCTL_REQUEST_EVENT, FALSE)))
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(ptym->input_available_event = get_event (INPUT_AVAILABLE_EVENT, FALSE)))
|
|
return FALSE;
|
|
|
|
char buf[40];
|
|
__small_sprintf (buf, OUTPUT_MUTEX, ntty);
|
|
if (!(ptym->output_mutex = CreateMutex (&sec_all, FALSE, buf)))
|
|
{
|
|
termios_printf ("can't create %s", buf);
|
|
set_errno (ENOENT);
|
|
return FALSE;
|
|
}
|
|
|
|
__small_sprintf (buf, INPUT_MUTEX, ntty);
|
|
if (!(ptym->input_mutex = CreateMutex (&sec_all, FALSE, buf)))
|
|
{
|
|
termios_printf ("can't create %s", buf);
|
|
set_errno (ENOENT);
|
|
return FALSE;
|
|
}
|
|
|
|
ProtectHandle1 (ptym->output_mutex, output_mutex);
|
|
ProtectHandle1 (ptym->input_mutex, input_mutex);
|
|
winsize.ws_col = 80;
|
|
winsize.ws_row = 25;
|
|
|
|
termios_printf("tty%d opened", ntty);
|
|
return TRUE;
|
|
}
|