4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-01-27 17:40:37 +08:00
Takashi Yano 3721a756b0 Cygwin: console: Make the console accessible from other terminals.
Previously, the console device could not be accessed from other terminals.
Due to this limitation, GNU screen and tmux cannot be opened in console.
With this patch, console device can be accessed from other TTYs, such as
other consoles or ptys. Thanks to this patch, screen and tmux get working
in console.

Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
2022-12-22 21:05:31 +09:00

398 lines
10 KiB
Plaintext

%import {
#include "winsup.h"
#include "devices.h"
#include "sys/cygwin.h"
#include "tty.h"
#include "pinfo.h"
#include "shared_info.h"
#include "path.h"
#include "fhandler.h"
#include "ntdll.h"
#include "dtable.h"
#include "cygheap.h"
typedef const _device *KR_device_t;
}
%type KR_device_t
%local {
static int
exists_internal (const device&)
{
return false;
}
static int
exists (const device&)
{
return true;
}
/* Check existence of POSIX devices backed by real NT devices. */
static int
exists_ntdev (const device& dev)
{
WCHAR wpath[MAX_PATH];
UNICODE_STRING upath;
OBJECT_ATTRIBUTES attr;
HANDLE h;
NTSTATUS status;
sys_mbstowcs (wpath, MAX_PATH, dev.native ());
RtlInitUnicodeString (&upath, wpath);
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
/* Except for the serial IO devices, the native paths are
direct device paths, not symlinks, so every status code
except for "NOT_FOUND" means the device exists. */
status = NtOpenSymbolicLinkObject (&h, SYMBOLIC_LINK_QUERY, &attr);
switch (status)
{
case STATUS_OBJECT_NAME_NOT_FOUND:
case STATUS_OBJECT_PATH_NOT_FOUND:
return false;
case STATUS_SUCCESS:
NtClose (h);
default:
break;
}
return true;
}
/* Don't list via readdir but allow as a direct reference. */
static int
exists_ntdev_silent (const device& dev)
{
return exists_ntdev (dev) ? -1 : false;
}
static BOOL CALLBACK
enum_cons_dev (HWND hw, LPARAM lp)
{
unsigned long *bitmask = (unsigned long *) lp;
HANDLE h = NULL;
fhandler_console::console_state *cs;
if ((cs = fhandler_console::open_shared_console (hw, h)))
{
*bitmask |= (1UL << cs->tty_min_state.getntty ());
UnmapViewOfFile ((void *) cs);
CloseHandle (h);
}
return TRUE;
}
static int
exists_console (const device& dev)
{
fh_devices devn = *const_cast<device *> (&dev);
switch (devn)
{
case FH_CONSOLE:
case FH_CONIN:
case FH_CONOUT:
return cygheap && cygheap->ctty && cygheap->ctty->is_console ()
&& fhandler_console::exists ();
default:
if (dev.get_minor () < MAX_CONS_DEV)
{
unsigned long bitmask = 0;
EnumWindows (enum_cons_dev, (LPARAM) &bitmask);
return bitmask & (1UL << dev.get_minor ());
}
return false;
}
}
static int
exists_pty (const device& dev)
{
/* Only existing slave ptys. */
return cygwin_shared->tty.connect (dev.get_minor ()) != -1;
}
const _device dev_cygdrive_storage =
{"/cygdrive", {FH_CYGDRIVE}, "", exists};
const _device dev_fs_storage =
{"", {FH_FS}, "", exists};
const _device dev_proc_storage =
{"", {FH_PROC}, "", exists};
const _device dev_procnet_storage =
{"", {FH_PROCNET}, "", exists};
const _device dev_procsys_storage =
{"", {FH_PROCSYS}, "", exists};
const _device dev_procsysvipc_storage =
{"", {FH_PROCSYSVIPC}, "", exists};
const _device dev_netdrive_storage =
{"", {FH_NETDRIVE}, "", exists};
const _device dev_registry_storage =
{"", {FH_REGISTRY}, "", exists_internal};
const _device dev_piper_storage =
{"", {FH_PIPER}, "", exists_internal};
const _device dev_pipew_storage =
{"", {FH_PIPEW}, "", exists_internal};
const _device dev_signalfd_storage =
{"", {FH_SIGNALFD}, "", exists_internal};
const _device dev_timerfd_storage =
{"", {FH_TIMERFD}, "", exists_internal};
const _device dev_mqueue_storage =
{"", {FH_MQUEUE}, "", exists_internal};
const _device dev_socket_storage =
{"", {FH_SOCKET}, "", exists_internal};
const _device dev_af_inet_storage =
{"", {FH_INET}, "", exists_internal};
const _device dev_af_unix_storage =
{"", {FH_UNIX}, "", exists_internal};
const _device dev_af_local_storage =
{"", {FH_LOCAL}, "", exists_internal};
const _device dev_bad_storage =
{"", {FH_NADA}, "", exists_internal};
const _device dev_error_storage =
{"", {FH_ERROR}, "", exists_internal};
#define BRACK(x) {devn: x}
%storage_here
}
/* Internal devices below are prefixed with a ":". This moves them out of
the POSIX namespace. */
%%
"/dev", BRACK(FH_DEV), "", exists, S_IFDIR
"/dev/tty", BRACK(FH_TTY), "/dev/tty", exists, S_IFCHR
"/dev/pty%(0-127)d", BRACK(FHDEV(DEV_PTYS_MAJOR, {$1})), "/dev/pty{$1}", exists_pty, S_IFCHR, =ptys_dev
":ptym%(0-127)d", BRACK(FHDEV(DEV_PTYM_MAJOR, {$1})), "/dev/ptym{$1}", exists_internal, S_IFCHR, =ptym_dev
"/dev/cons%(0-127)d", BRACK(FHDEV(DEV_CONS_MAJOR, {$1})), "/dev/cons{$1}", exists_console, S_IFCHR, =cons_dev
"/dev/console", BRACK(FH_CONSOLE), "/dev/console", exists_console, S_IFCHR, =console_dev
"/dev/ptmx", BRACK(FH_PTMX), "/dev/ptmx", exists, S_IFCHR
"/dev/windows", BRACK(FH_WINDOWS), "\\Device\\Null", exists_ntdev, S_IFCHR
"/dev/dsp", BRACK(FH_OSS_DSP), "\\Device\\Null", exists_ntdev, S_IFCHR
"/dev/conin", BRACK(FH_CONIN), "/dev/conin", exists_console, S_IFCHR
"/dev/conout", BRACK(FH_CONOUT), "/dev/conout", exists_console, S_IFCHR
"/dev/null", BRACK(FH_NULL), "\\Device\\Null", exists_ntdev, S_IFCHR
"/dev/zero", BRACK(FH_ZERO), "\\Device\\Null", exists_ntdev, S_IFCHR
"/dev/full", BRACK(FH_FULL), "\\Device\\Null", exists_ntdev, S_IFCHR
"/dev/random", BRACK(FH_RANDOM), "\\Device\\Null", exists_ntdev, S_IFCHR
"/dev/urandom", BRACK(FH_URANDOM), "\\Device\\Null", exists_ntdev, S_IFCHR, =urandom_dev
"/dev/clipboard", BRACK(FH_CLIPBOARD), "\\Device\\Null", exists_ntdev, S_IFCHR
"/dev/com%(1-16)d", BRACK(FHDEV(DEV_SERIAL_MAJOR, {$1 - 1})), "\\??\\COM{$1}", exists_ntdev_silent, S_IFCHR
"/dev/ttyS%(0-127)d", BRACK(FHDEV(DEV_SERIAL_MAJOR, {$1})), "\\??\\COM{$1 + 1}", exists_ntdev, S_IFCHR
":pipe", BRACK(FH_PIPE), "/dev/pipe", exists_internal, S_IFCHR
":fifo", BRACK(FH_FIFO), "/dev/fifo", exists_internal, S_IFCHR
"/dev/st%(0-127)d", BRACK(FHDEV(DEV_TAPE_MAJOR, {$1})), "\\Device\\Tape{$1}", exists_ntdev, S_IFBLK
"/dev/nst%(0-127)d", BRACK(FHDEV(DEV_TAPE_MAJOR, {$1 + 128})), "\\Device\\Tape{$1}", exists_ntdev, S_IFBLK
"/dev/fd%(0-15)d", BRACK(FHDEV(DEV_FLOPPY_MAJOR, {$1})), "\\Device\\Floppy{$1}", exists_ntdev, S_IFBLK
"/dev/scd%(0-15)d", BRACK(FHDEV(DEV_CDROM_MAJOR, {$1})), "\\Device\\CdRom{$1}", exists_ntdev, S_IFBLK
"/dev/sr%(0-15)d", BRACK(FHDEV(DEV_CDROM_MAJOR, {$1})), "\\Device\\CdRom{$1}", exists_ntdev, S_IFBLK
"/dev/fd", BRACK(FH_DEV_FD), "/proc/self/fd", exists, S_IFLNK
"/dev/stdin", BRACK(FH_DEV_FD), "/proc/self/fd/0", exists, S_IFLNK
"/dev/stdout", BRACK(FH_DEV_FD), "/proc/self/fd/1", exists, S_IFLNK
"/dev/stderr", BRACK(FH_DEV_FD), "/proc/self/fd/2", exists, S_IFLNK
%other {return NULL;}
%%
#undef BRACK
const _device *dev_storage_end = dev_storage
+ (sizeof dev_storage / sizeof dev_storage[0]);
/* Convert disk/partition to major/minor */
static void
conv_dp_to_mm (int drive, int part, _major_t &major, _minor_t &minor)
{
if (part >= 16)
{
major = DEV_SD_HIGHPART_START + drive / 5;
drive %= 5;
minor = (part - 16) + 48 * drive;
return;
}
if (drive < ('q' - 'a')) /* /dev/sda -to- /dev/sdp */
major = DEV_SD_MAJOR;
else if (drive < 32) /* /dev/sdq -to- /dev/sdaf */
{
major = DEV_SD1_MAJOR;
drive -= 'q' - 'a';
}
else if (drive < 48) /* /dev/sdag -to- /dev/sdav */
{
major = DEV_SD2_MAJOR;
drive -= 32;
}
else if (drive < 64) /* /dev/sdaw -to- /dev/sdbl */
{
major = DEV_SD3_MAJOR;
drive -= 48;
}
else if (drive < 80) /* /dev/sdbm -to- /dev/sdcb */
{
major = DEV_SD4_MAJOR;
drive -= 64;
}
else if (drive < 96) /* /dev/sdcc -to- /dev/sdcr */
{
major = DEV_SD5_MAJOR;
drive -= 80;
}
else if (drive < 112) /* /dev/sdcs -to- /dev/sddh */
{
major = DEV_SD6_MAJOR;
drive -= 96;
}
/* NOTE: This will cause multiple /dev/sddx entries in
/proc/partitions if there are more than 128 devices */
else /* /dev/sddi -to- /dev/sddx */
{
major = DEV_SD7_MAJOR;
drive -= 112;
}
minor = part + (drive * 16);
}
#define DISK_PREFIX "/dev/sd"
#define DP_LEN (sizeof (DISK_PREFIX) - 1)
static const char *hd_pattern = "\\Device\\Harddisk%u\\Partition%u";
void
device::parse (const char *s)
{
size_t len = strlen (s);
const _device *dev = KR_find_keyword (s, len);
if (!dev)
{
/* /dev/sd* devices have 8192 entries, given that we support 128 disks
with up to 64 partitions. Handling them with shilka raises the size
of devices.o from ~250K to ~2 Megs. So we handle them here manually
to save this space. */
int drive = 0, part = 0;
const char *pos = s + DP_LEN;
/* Generic check for /dev/sd[a-z] prefix */
if (len <= DP_LEN || strncmp (s, DISK_PREFIX, DP_LEN)
|| pos[0] < 'a' || pos[0] > 'z')
goto no_disk;
/* /dev/sdd[a-x]? */
if (pos[0] == 'd' && pos[1] >= 'a' && pos[1] <= 'x')
{
drive = 104 + (pos[1] - 'a');
++pos;
}
/* /dev/sd[a-c][a-z]? */
else if (pos[0] <= 'c' && pos[1] >= 'a' && pos[1] <= 'z')
{
drive = 26 + (pos[0] - 'a') * 26 + (pos[1] - 'a');
++pos;
}
else
drive = (pos[0] - 'a');
/* Check next position in string for partition number. */
++pos;
/* No partition number, equivalent to Windows partition 0. */
if (!pos[0])
;
/* First digit must not be 0. */
else if (pos[0] < '1' || pos[0] > '9')
goto no_disk;
else if (!pos[1])
part = (pos[0] - '0');
else if (pos[1] < '0' || pos[1] > '9' || pos[2] != '\0')
goto no_disk;
else
{
part = (pos[0] - '0') * 10 + (pos[1] - '0');
if (part > 63)
goto no_disk;
}
char buf[sizeof *hd_pattern + 32];
__small_sprintf (buf, hd_pattern, drive, part);
native (buf, false);
if (exists_ntdev (*this))
{
name (s, true);
conv_dp_to_mm (drive, part, d.major, d.minor);
native (buf, true);
exists_func = exists_ntdev;
_mode = S_IFBLK;
lives_in_dev = dev_on_fs = false;
return;
}
no_disk:
*this = *fs_dev;
}
else
*this = *dev;
}
void
device::init ()
{
/* nothing to do... yet */
}
void
device::parse (_major_t major, _minor_t minor)
{
dev_t devn = FHDEV (major, minor);
d.devn = 0;
for (const _device *devidx = dev_storage; devidx < dev_storage_end; devidx++)
if (devidx->d.devn == devn)
{
*this = *devidx;
break;
}
if (!*this)
d.devn = FHDEV (major, minor);
}
void
device::parse (dev_t dev)
{
parse (_major (dev), _minor (dev));
}
void
device::parsedisk (int drive, int part)
{
char buf[sizeof ("/dev/sddx63")], *bp;
conv_dp_to_mm (drive, part, d.major, d.minor);
bp = stpcpy (buf, "/dev/sd");
if (drive >= 26)
{
drive -= 26;
*bp++ = drive / 26 + 'a';
drive %= 26;
}
*bp++ = drive + 'a';
if (part)
{
if (part >= 10)
{
*bp++ = part / 10 + '0';
part %= 10;
}
*bp++ = part + '0';
}
*bp = '\0';
name (buf, true);
}