4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-01 12:00:35 +08:00
Takashi Yano via Cygwin-patches 72770148ad Cygwin: pty: Prevent pty from changing code page of parent console.
- After commit 232fde0e, pty changes console code page when the first
  non-cygwin app is executed. If pty is started in real console device,
  pty changes the code page of root console. This causes very annoying
  result because changing code page changes the font of command prompt
  if console is in legacy mode. This patch avoids this by creating a
  new invisible console for the first pty started in console device.
2021-01-18 14:18:43 +01:00

314 lines
6.1 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;
h_pseudo_console = NULL;
switch_to_pcon_in = false;
mask_switch_to_pcon_in = false;
pcon_pid = 0;
term_code_page = 0;
pcon_last_time = 0;
pcon_start = false;
pcon_cap_checked = false;
has_csi6n = false;
has_set_title = false;
do_not_resize_pcon = false;
need_invisible_console = false;
invisible_console_pid = 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 ();
}
void
tty::wait_pcon_fwd (void)
{
/* The forwarding in pseudo console sometimes stops for
16-32 msec even if it already has data to transfer.
If the time without transfer exceeds 32 msec, the
forwarding is supposed to be finished. pcon_last_time
is reset to GetTickCount() in pty master forwarding
thread when the last data is transfered. */
const int sleep_in_pcon = 16;
const int time_to_wait = sleep_in_pcon * 2 + 1/* margine */;
pcon_last_time = GetTickCount ();
while (GetTickCount () - pcon_last_time < time_to_wait)
{
int tw = time_to_wait - (GetTickCount () - pcon_last_time);
cygwait (tw);
}
}