On Nov 26 10:08, Konstantin Kouptsov wrote: > On Windows, if I compile it using a Microsoft compiler: > > C: > cl /out:checktty.exe checktty.c > > the program behaves correctly when I run it from a DOS prompt or from a > Cywin's bash prompt. However, if I connect to the Windows computer running > Cygwin's sshd service from another Linux or Windows computer, it always gives > the same result: > > $ ./checktty.exe > not a tty > > $ ./checktty.exe < checktty.c > not a tty > > (When I compile with Cygwin's gcc, everything is fine) > > What happens here?
Cygwin pseudo ttys are implemented as pipes, and the msvcrt runtime has no idea about that. It sees a pipe and that's no tty from its POV. > Given that I must compile the program using Microsoft's compiler on Windows, > how this can be worked around? The workaround is to implement your own isatty function which recognizes Cygwin pseudo ttys as well. I had a customer asking this question, too, at one point and I sent them example code. I attached it to this mail. HTH, Corinna -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Project Co-Leader cygwin AT cygwin DOT com Red Hat
#include <stdio.h> #include <io.h> #include <errno.h> #include <wchar.h> #include <windows.h> #include <winternl.h> #ifndef __MINGW64_VERSION_MAJOR /* MS winternl.h defines FILE_INFORMATION_CLASS, but with only a different single member. */ enum FILE_INFORMATION_CLASSX { FileNameInformation = 9 }; typedef struct _FILE_NAME_INFORMATION { ULONG FileNameLength; WCHAR FileName[1]; } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; NTSTATUS (NTAPI *pNtQueryInformationFile) (HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASSX); #else NTSTATUS (NTAPI *pNtQueryInformationFile) (HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS); #endif int isatty (int fd) { HANDLE fh; NTSTATUS status; IO_STATUS_BLOCK io; long buf[66]; /* NAME_MAX + 1 + sizeof ULONG */ PFILE_NAME_INFORMATION pfni = (PFILE_NAME_INFORMATION) buf; PWCHAR cp; /* First check using _isatty. Note that this returns the wrong result for NUL, for instance! Workaround is not to use _isatty at all, but rather GetFileType plus object name checking. */ if (_isatty (fd)) return 1; /* Now fetch the underlying HANDLE. */ fh = (HANDLE) _get_osfhandle (fd); if (!fh || fh == INVALID_HANDLE_VALUE) { errno = EBADF; return 0; } /* Must be a pipe. */ if (GetFileType (fh) != FILE_TYPE_PIPE) goto no_tty; /* Calling the native NT function NtQueryInformationFile is required to support pre-Vista systems. If that's of no concern, Vista introduced the GetFileInformationByHandleEx call with the FileNameInfo info class, which can be used instead. */ if (!pNtQueryInformationFile) { pNtQueryInformationFile = (NTSTATUS (NTAPI *)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS)) GetProcAddress (GetModuleHandle ("ntdll.dll"), "NtQueryInformationFile"); if (!pNtQueryInformationFile) goto no_tty; } if (!NT_SUCCESS (pNtQueryInformationFile (fh, &io, pfni, sizeof buf, FileNameInformation))) goto no_tty; /* The filename is not guaranteed to be NUL-terminated. */ pfni->FileName[pfni->FileNameLength / sizeof (WCHAR)] = L'\0'; /* Now check the name pattern. The filename of a Cygwin pseudo tty pipe looks like this: \cygwin-%16llx-pty%d-{to,from}-master %16llx is the hash of the Cygwin installation, (to support multiple parallel installations), %d id the pseudo tty number, "to" or "from" differs the pipe direction. "from" is a stdin, "to" a stdout-like pipe. */ cp = pfni->FileName; if (!wcsncmp (cp, L"\\cygwin-", 8) && !wcsncmp (cp + 24, L"-pty", 4)) { cp = wcschr (cp + 28, '-'); if (!cp) goto no_tty; if (!wcscmp (cp, L"-from-master") || !wcscmp (cp, L"-to-master")) return 1; } no_tty: errno = EINVAL; return 0; } int main () { if (isatty(0)) printf("tty\n"); else printf("not a tty\n"); return 0; }
-- Problem reports: http://cygwin.com/problems.html FAQ: http://cygwin.com/faq/ Documentation: http://cygwin.com/docs.html Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple