| %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" |
| |
| 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 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 fhandler_console::exists (); |
| default: |
| /* Only show my own console device (for now?) */ |
| return iscons_dev (myself->ctty) && myself->ctty == devn; |
| } |
| } |
| |
| 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_tcp_storage = |
| {"", {FH_TCP}, "", exists_internal}; |
| |
| const _device dev_udp_storage = |
| {"", {FH_UDP}, "", exists_internal}; |
| |
| const _device dev_stream_storage = |
| {"", {FH_STREAM}, "", exists_internal}; |
| |
| const _device dev_dgram_storage = |
| {"", {FH_DGRAM}, "", 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-63)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/kmsg", BRACK(FH_KMSG), "\\Device\\MailSlot\\cygwin\\dev\\kmsg", exists_ntdev, S_IFCHR |
| %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); |
| } |