mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-01-15 11:00:04 +08:00
0301bfd0ac
functionality. * cygheap.cc (init_cheap): Move cygheap_max calculation to _csbrk. (_csbrk): Reorganize to not assume first allocation is <= 1 page. (cygheap_setup_for_child): Mark protected handle as inheritable. * cygheap.h (cygheap_debug): New struct. (init_cygheap): Add new structure when debugging. * dcrt0.cc (dll_crt0_1): Remove call to debug_init. Close ppid_handle here, if appropriate. Don't protect subproc_ready, since it is already protected in the parent. Call memory_init prior to ProtectHandle to ensure that cygheap is set up. Call debug_fixup_after_fork_exec when appropriate. (_dll_crt0): Don't close ppid_handle here. * debug.cc: Use cygheap debug structure rather than static elements throughout. (add_handle): Don't issue a warning if attempt to protect handle in exactly the same way from exactly the same place. Add pid info to warning output. Accept additional argument controlling whether handle is to be inherited. Add pid to stored information. (debug_fixup_after_fork_exec): Renamed from debug_fixup_after_fork. Reorganize to avoid erroneously skipping handles. (mark_closed): Add pid info to warning output. (setclexec): Rename from setclexec_pid. * fhandler.cc (fhandler_base::get_default_fmode): Minor reorg. (fhandler_base::fstat): Add debugging output. (fhandler_base::set_inheritance): Call setclexec rather than setclexec_pid. (fhandler_base::fork_fixup): Ditto. * fhandler_console.cc (get_tty_stuff): Mark protected handle as inheritable. * fhandler_tty.cc (fhandler_tty_slave::open): Ditto. * tty.cc (tty::make_pipes): Ditto. (tty::common_init): Ditto. * fork.cc (fork_parent): Ditto. (fork_child): Close protected handles with correct name. Remove debug_fixup_after_fork call. * fhandler_socket.cc (fhandler_socket::create_secret_event): Mark protected handle as inheritable/non-inheritable, as appropriate. * shared.cc (memory_init): Mark protected handle as inheritable. Call debug_init here. * sigproc.cc (wait_sig): Close protected handle with correct name. * spawn.cc (spawn_guts): Rename spr to subproc_ready and mark it as inheritable. * exceptions.cc (debugger_command): Try to run dumper.exe, if found. * syscalls.cc (fstat64): Don't follow symlinks for path_conv lookup since path is already resolved.
452 lines
9.9 KiB
C++
452 lines
9.9 KiB
C++
/* 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 <errno.h>
|
|
#include <unistd.h>
|
|
#include <utmp.h>
|
|
#include <wingdi.h>
|
|
#include <winuser.h>
|
|
#include <sys/cygwin.h>
|
|
#include "cygerrno.h"
|
|
#include "security.h"
|
|
#include "fhandler.h"
|
|
#include "path.h"
|
|
#include "dtable.h"
|
|
#include "cygheap.h"
|
|
#include "pinfo.h"
|
|
#include "cygwin/cygserver_transport.h"
|
|
#include "cygwin/cygserver.h"
|
|
#include "shared_info.h"
|
|
|
|
extern fhandler_tty_master *tty_master;
|
|
|
|
extern "C"
|
|
int
|
|
grantpt (int fd)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
extern "C"
|
|
int
|
|
unlockpt (int fd)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
extern "C"
|
|
int
|
|
ttyslot (void)
|
|
{
|
|
if (NOTSTATE (myself, PID_USETTY))
|
|
return -1;
|
|
return myself->ctty;
|
|
}
|
|
|
|
void __stdcall
|
|
tty_init (void)
|
|
{
|
|
if (!myself->ppid_handle && NOTSTATE (myself, PID_CYGPARENT))
|
|
cygheap->fdtab.get_debugger_info ();
|
|
|
|
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 *)
|
|
cygheap->fdtab.build_fhandler (-1, FH_TTYM, "/dev/ttym", NULL, 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);
|
|
CloseHandle (tty_master->inuse);
|
|
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, FALSE, 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)
|
|
{
|
|
output_stopped = 0;
|
|
setsid (0);
|
|
pgid = 0;
|
|
hwnd = NULL;
|
|
to_slave = NULL;
|
|
from_slave = NULL;
|
|
was_opened = 0;
|
|
}
|
|
|
|
HANDLE
|
|
tty::get_event (const char *fmt, BOOL manual_reset)
|
|
{
|
|
HANDLE hev;
|
|
char buf[40];
|
|
|
|
__small_sprintf (buf, fmt, ntty);
|
|
if (!(hev = CreateEvent (&sec_all, 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
ProtectHandle1INH (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;
|
|
}
|
|
ProtectHandle1INH (from_slave, from_pty);
|
|
termios_printf ("tty%d from_slave %p, to_slave %p", ntty, from_slave,
|
|
to_slave);
|
|
|
|
DWORD pipe_mode = PIPE_NOWAIT;
|
|
if (!SetNamedPipeHandleState (to_slave, &pipe_mode, NULL, NULL))
|
|
termios_printf ("can't set to_slave to non-blocking mode");
|
|
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) */
|
|
|
|
/* FIXME: we shold NOT set the security wide open when the
|
|
daemon is running
|
|
*/
|
|
if (wincap.has_security () && cygserver_running != CYGSERVER_OK &&
|
|
(SetKernelObjectSecurity (hMainProc, DACL_SECURITY_INFORMATION,
|
|
get_null_sd ()) == FALSE))
|
|
system_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)))
|
|
return FALSE;
|
|
if (!(ptym->ioctl_done_event = get_event (IOCTL_DONE_EVENT)))
|
|
return FALSE;
|
|
if (!(ptym->ioctl_request_event = get_event (IOCTL_REQUEST_EVENT)))
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(ptym->input_available_event = get_event (INPUT_AVAILABLE_EVENT, TRUE)))
|
|
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;
|
|
}
|
|
|
|
ProtectHandle1INH (ptym->output_mutex, output_mutex);
|
|
ProtectHandle1INH (ptym->input_mutex, input_mutex);
|
|
winsize.ws_col = 80;
|
|
winsize.ws_row = 25;
|
|
|
|
termios_printf ("tty%d opened", ntty);
|
|
return TRUE;
|
|
}
|