Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342/* * CTTY.C - ctty (Change TTY) command. * * This command redirects the first three standard handles * stdin, stdout, stderr to another terminal. * * * History: * * 14 Aug 1998 (John P Price) * - Created dummy command. * * 2000/01/14 ska * + Added to change the first three handles to the given device name * + Supports only redirection of stdin and stdout, e.g.: * C:\> CTTY COM1 >file * -or- * C:\> echo Hallo | CTTY COM1 | echo du * The CTTY command effects the commands on the _next_ line. * * 20 Oct 2016 (Hermes Belusca-Maito) * Port it to NT. */
#include "precomp.h"
#if defined(INCLUDE_CMD_CTTY) && defined(FEATURE_REDIRECTION)
static WORDCheckTerminalDeviceType(IN LPCTSTR pszName){ /* Console reserved "file" names */ static const LPCWSTR DosLPTDevice = L"LPT"; static const LPCWSTR DosCOMDevice = L"COM"; static const LPCWSTR DosPRNDevice = L"PRN"; static const LPCWSTR DosAUXDevice = L"AUX"; static const LPCWSTR DosCONDevice = L"CON"; static const LPCWSTR DosNULDevice = L"NUL";
LPCWSTR DeviceName; ULONG DeviceNameInfo; WORD DeviceType = 0; // 0: Unknown; 1: CON; 2: COM etc...
#ifndef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16 /* Convert from the current process/thread's codepage to UTF-16 */ DWORD len = strlen(pszName) + 1; WCHAR *buffer = cmd_alloc(len * sizeof(WCHAR)); if (!buffer) { // SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } len = (DWORD)MultiByteToWideChar(CP_THREAD_ACP, // CP_ACP, CP_OEMCP 0, pszName, (INT)len, buffer, (INT)len); DeviceName = buffer;#else DeviceName = pszName;#endif
/* * Check whether we deal with a DOS device, and if so, * strip the path till the file name. * Therefore, things like \\.\CON or C:\some_path\COM1 * are transformed into CON or COM1, for example. */ DeviceNameInfo = RtlIsDosDeviceName_U(DeviceName); if (DeviceNameInfo != 0) { DeviceName = (LPCWSTR)((ULONG_PTR)DeviceName + ((DeviceNameInfo >> 16) & 0xFFFF));
if (_wcsnicmp(DeviceName, DosCONDevice, 3) == 0) { DeviceType = 1; } else if ( _wcsnicmp(DeviceName, DosLPTDevice, 3) == 0 || _wcsnicmp(DeviceName, DosCOMDevice, 3) == 0 || _wcsnicmp(DeviceName, DosPRNDevice, 3) == 0 || _wcsnicmp(DeviceName, DosAUXDevice, 3) == 0 || _wcsnicmp(DeviceName, DosNULDevice, 3) == 0 ) { DeviceType = 2; } // else DeviceType = 0; }
#ifndef _UNICODE cmd_free(buffer);#endif
return DeviceType;}
/* * See also redir.c!PerformRedirection(). * * The CTTY command allows only the usage of CON, COM, AUX, LPT, PRN and NUL * DOS devices as valid terminal devices. Everything else is forbidden. * * CTTY does not set ERRORLEVEL on error. */INT cmd_ctty(LPTSTR param){ static SECURITY_ATTRIBUTES SecAttr = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
BOOL Success; WORD DeviceType; HANDLE hDevice, hStdHandles[3]; // hStdIn, hStdOut, hStdErr;
/* The user asked for help */ if (_tcsncmp(param, _T("/?"), 2) == 0) { ConOutResPaging(TRUE, STRING_CTTY_HELP); return 0; }
if (!*param) { error_req_param_missing(); return 1; }
/* Check whether this is a valid terminal device name */ DeviceType = CheckTerminalDeviceType(param); if (DeviceType == 1) { /* * Special case for CON device. * * We do not open CON with GENERIC_READ or GENERIC_WRITE as is, * but instead we separately open CONIN$ and CONOUT$ with both * GENERIC_READ | GENERIC_WRITE access. * We do so because otherwise, opening in particular CON with GENERIC_WRITE * only would open CONOUT$ with an handle not passing the IsConsoleHandle() * test, meaning that we could not use the full console functionalities. */ BOOL bRetry = FALSE;
RetryOpenConsole: /* * If we previously failed in opening handles to the console, * this means the existing console is almost destroyed. * Close the existing console and allocate and open a new one. */ if (bRetry) { FreeConsole(); if (!AllocConsole()) return 1; }
/* Attempt to retrieve a handle for standard input */ hStdHandles[0] = CreateFile(_T("CONIN$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &SecAttr, OPEN_EXISTING, 0, NULL); if (hStdHandles[0] == INVALID_HANDLE_VALUE) { // TODO: Error // error_no_rw_device(param);
if (bRetry) return 1; bRetry = TRUE; goto RetryOpenConsole; }
/* Attempt to retrieve a handle for standard output. * Note that GENERIC_READ is needed for IsConsoleHandle() to succeed afterwards. */ hStdHandles[1] = CreateFile(_T("CONOUT$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &SecAttr, OPEN_EXISTING, 0, NULL); if (hStdHandles[1] == INVALID_HANDLE_VALUE) { // TODO: Error // error_no_rw_device(param);
CloseHandle(hStdHandles[0]);
if (bRetry) return 1; bRetry = TRUE; goto RetryOpenConsole; }
/* Duplicate a handle for standard error */ Success = DuplicateHandle(GetCurrentProcess(), hStdHandles[1], GetCurrentProcess(), &hStdHandles[2], 0, // GENERIC_WRITE, TRUE, DUPLICATE_SAME_ACCESS /* 0 */); if (!Success) { // TODO: Error // error_no_rw_device(param); CloseHandle(hStdHandles[1]); CloseHandle(hStdHandles[0]); return 1; } } else if (DeviceType == 2) { /* * COM and the other devices can only be opened once. * Since we need different handles, we need to duplicate them. */
/* Attempt to retrieve a handle to the device for read/write access */ hDevice = CreateFile(param, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &SecAttr, OPEN_EXISTING, 0, // FILE_FLAG_OVERLAPPED, // 0, NULL); if (hDevice == INVALID_HANDLE_VALUE) { // TODO: Error // error_no_rw_device(param); return 1; }
/* Duplicate a handle for standard input */ Success = DuplicateHandle(GetCurrentProcess(), hDevice, GetCurrentProcess(), &hStdHandles[0], GENERIC_READ, TRUE, 0); if (!Success) { // TODO: Error // error_no_rw_device(param); CloseHandle(hDevice); return 1; }
/* Duplicate a handle for standard output */ Success = DuplicateHandle(GetCurrentProcess(), hDevice, GetCurrentProcess(), &hStdHandles[1], GENERIC_WRITE, TRUE, 0); if (!Success) { // TODO: Error // error_no_rw_device(param); CloseHandle(hStdHandles[0]); CloseHandle(hDevice); return 1; }
/* Duplicate a handle for standard error */ Success = DuplicateHandle(GetCurrentProcess(), hDevice, GetCurrentProcess(), &hStdHandles[2], GENERIC_WRITE, TRUE, 0); if (!Success) { // TODO: Error // error_no_rw_device(param); CloseHandle(hStdHandles[1]); CloseHandle(hStdHandles[0]); CloseHandle(hDevice); return 1; }
/* Now get rid of the main device handle */ CloseHandle(hDevice); } else { ConOutResPrintf(STRING_ERROR_INVALID_DEVICE, param); return 1; }
#if 0 /* Now change the file descriptors: 0 := rdonly 1,2 := wronly
if CTTY is called within a pipe or its I/O is redirected, oldinfd or oldoutfd is not equal to -1. In such case the old*fd is modified in order to effect the file descriptor after the redirections are restored. Otherwise a pipe or redirection would left CTTY in a half-made status. */ // int failed; failed = dup2(f, 2); /* no redirection support */ if(oldinfd != -1) dos_close(oldinfd); oldinfd = f; if(oldoutfd != -1) dos_close(oldoutfd); if((oldoutfd = dup(f)) == -1) failed = 1;
if(failed) error_ctty_dup(param);
return failed;#endif
/* Now set the standard handles */
hDevice = GetHandle(0); if (hDevice != INVALID_HANDLE_VALUE) CloseHandle(hDevice); SetHandle(0, hStdHandles[0]);
hDevice = GetHandle(1); if (hDevice != INVALID_HANDLE_VALUE) CloseHandle(hDevice); SetHandle(1, hStdHandles[1]);
hDevice = GetHandle(2); if (hDevice != INVALID_HANDLE_VALUE) CloseHandle(hDevice); SetHandle(2, hStdHandles[2]);
return 0;}
#endif /* INCLUDE_CMD_CTTY && FEATURE_REDIRECTION */
/* EOF */